Java JNA:如何在结构中指定可变长度(0+;)数组?
示例结构,其中Java JNA:如何在结构中指定可变长度(0+;)数组?,java,arrays,structure,jna,Java,Arrays,Structure,Jna,示例结构,其中count是数组中的字节数,可以是0。我想在Java中分配新实例,并读取本机分配的实例 公共类VarArray扩展结构{ 公共字节dummy0; 公众短消息1; 公共整数计数; 公共字节[]数组; } 在结构中不允许使用数组=新字节[0] 如果计数为0,则声明默认值array=new byte[1]将从未分配的地址读取 删除数组字段可以读取,因为我可以从指针偏移量Structure.size()访问字节。[编辑:不正确,取决于填充]。但是,对于分配新实例,我需要手动确定字段大小和
count
是数组中的字节数,可以是0。我想在Java中分配新实例,并读取本机分配的实例
公共类VarArray扩展结构{
公共字节dummy0;
公众短消息1;
公共整数计数;
公共字节[]数组;
}
在结构中不允许使用数组=新字节[0]
如果计数为0,则声明默认值array=new byte[1]
将从未分配的地址读取
删除数组
字段可以读取,因为我可以从指针偏移量Structure.size()访问字节。
[编辑:不正确,取决于填充]。但是,对于分配新实例,我需要手动确定字段大小和对齐填充,以便分配正确的内存大小
我有一个使用两种类型的解决方案—一种是不带array
的,用于本机分配和0计数的Java分配实例,另一种是带有array
的子类型,用于Java分配的1+计数实例。这似乎有些臃肿,尤其是对于所需的锅炉板代码
有更好的办法吗?
或者是一种简单的方法来计算字段大小和对齐方式,这样一种类型就足够了
导入java.util.array;
导入java.util.List;
导入com.sun.jna.Pointer;
导入com.sun.jna.Structure;
公共类JnaStructTester{
/**
*对于本机分配的和0计数的JNA分配实例。
*/
公共静态类VarArray扩展结构{
公共字节dummy0;
公众短消息1;
公共整数计数;
公共VarArray(){}
公共变量数组(指针p){
超级(p);
}
公共字节[]getArray(){
字节[]数组=新字节[计数];
如果(计数>0){
int offset=size();
getPointer().read(偏移量、数组、0、计数);
}
返回数组;
}
@凌驾
受保护列表getFieldOrder(){
返回列表(“dummy0”、“dummy1”、“count”);
}
}
/**
*对于1+个JNA分配的实例。
*/
公共静态类VarArrayX扩展了VarArray{
公共字节[]数组;
公共VarArrayX(){}
@凌驾
公共字节[]getArray(){
返回数组;
}
@凌驾
受保护列表getFieldOrder(){
返回列表(“dummy0”、“dummy1”、“count”、“array”);
}
}
公共静态void main(字符串[]args){
var va0=新的VarArrayX();
va0.dummy0=(字节)0xef;
va0.dummy1=(短)0xabcd;
va0.count=7;
va0.array=新字节[]{1,2,3,4,5,6,7};
va0.write();
var va1=新的VarArray();
va1.dummy0=(字节)0xab;
va1.dummy1=(短)0xcdef;
va1.write();
打印(新指针(Pointer.nativeValue(va0.getPointer()));
打印(新指针(Pointer.nativeValue(va1.getPointer()));
}
专用静态无效打印(指针p){
var va=新的VarArray(p);
va.read();
系统输出打印项次(va);
System.out.println(“byte[]array=“+Arrays.toString(va.getArray()));
System.out.println();
}
}
输出:
JnaStructTester$VarArray(native@0x7fb6835524b0) (8 bytes) {
byte dummy0@0=ffffffef
short dummy1@2=ffffabcd
int count@4=7
}
byte[] array=[1, 2, 3, 4, 5, 6, 7]
JnaStructTester$VarArray(native@0x7fb683551210) (8 bytes) {
byte dummy0@0=ffffffab
short dummy1@2=ffffcdef
int count@4=0
}
byte[] array=[]
JnaStructTester$VarArray(native@0x7fd85cf1ffb0) (12 bytes) {
short dummy0@0=4321
int dummy1@4=abcdef
byte count@8=7
byte array[7]@9=[B@4f2410ac
}
byte[] array=[1, 2, 3, 4, 5, 6, 7]
JnaStructTester$VarArray(native@0x7fd85cf20690) (12 bytes) {
short dummy0@0=4321
int dummy1@4=abcdef
byte count@8=0
byte array[0]@9=[B@722c41f4
}
byte[] array=[]
(我使用的是相当旧的JNA版本4.2.2)
更新(2020-01-07)
感谢Daniel Widdis的建议,这里有一个很好的解决方案
无法根据数组是否为空动态修改字段列表。当不包括变量数组字段时,布局被静态缓存,因此具有非空数组的未来实例将失败。相反:
在ensureAllocated()
中调整数组,以避免空数组错误
writeField()
仅在数组非空时写入字段
readField()
根据已读取的计数设置数组大小,如果计数为0,则跳过读取数组
通过在readField()
中将数组设置为正确的大小,将自动填充整个数组,无需手动创建
导入java.util.array;
导入java.util.List;
导入com.sun.jna.Pointer;
导入com.sun.jna.Structure;
公共类JnaStructTester{
公共静态类VarArray扩展结构{
公共短消息0;
公共部门1;
公共字节计数;
公共字节[]数组=新字节[0];
公共VarArray(){}
公共变量数组(字节[]数组){
this.count=(字节)array.length;
this.array=数组;
}
公共变量数组(指针p){
超级(p);
}
@凌驾
重新分配的受保护的空{
如果(计数==0)数组=新字节[1];
super.重新分配();
如果(计数==0)数组=新字节[0];
}
@凌驾
受保护的void writeField(StructField StructField){
if(structField.name.equals(“数组”)&&count==0)返回;
super.writeField(structField);
}
@凌驾
受保护对象读取字段(StructField StructField){
if(structField.name.equals(“数组”)){
数组=新字节[计数];
if(count==0)返回null;
}
返回super.readField(structField);
}
@凌驾
受保护列表getFieldOrder(){
返回列表(“dummy0”、“dummy1”、“count”、“array”);
}
}
公共静态void main(字符串[]args){
var va0=新的VARARY(新字节[]{1,2,3,4,5,6,7});
va0.dummy0=0x4321;
va0.dummy1=0xabcdef;
va0.write();
var va1=新的VarArray();
va1.dummy0=0x4321;
va1.dummy1=0xabcdef