JNA(Java):如何将指针数组传递给结构
JNA (Java): How to pass an array of pointers to struct?
我正在使用JNA从Java调用C库。
在我的 C 代码中,我有:
void printStructArray( SomeStruct **someStruct, int arraySize );
这需要一个指向结构的指针数组,即该方法这样做:
void printStructArray( SomeStruct **someStruct, int arraySize ) {
for( int i = 0; i < arraySize; i++ ) {
cout << "someStruct: " << someStruct[i]->aLong << " " << someStruct[i]->aString << " " << someStruct[i]->aDouble << endl;
}
}
这只是一个玩具示例,但我有一个实际的库,我想与之交谈,它需要相同类型的参数,但我认为使用玩具示例在这里更容易解释?
我已经尝试了各种各样的事情,但我不确定如何 (i) 在 JNA 中声明此函数 (ii) 在 JNA 中调用此函数。
我最近(失败)的尝试是:
SomeStruct.byReference[] structs = new SomeStruct.byReference[]{
new SomeStruct.byReference(123,"hey!",1.23),
new SomeStruct.byReference(456,"cool!",1.45),
new SomeStruct.byReference(789,"world!",1.67) };
PointerByReference pointerByReference = new PointerByReference(structs[0].getPointer());
JniTest.instance.printStructArray(pointerByReference, 3);
这会导致 SIGSEGV。
或者:
SomeStruct.byReference[] structs = (SomeStruct.byReference[]) new SomeStruct().toArray( new SomeStruct.byReference[]{
new SomeStruct.byReference(123,"hey!",1.23),
new SomeStruct.byReference(456,"cool!",1.45),
new SomeStruct.byReference(789,"world!",1.67) } );
PointerByReference pointerByReference = new PointerByReference(structs[0].getPointer());
JniTest.instance.printStructArray(pointerByReference, 3);
这会导致 ArrayStoreException
也试过这个:
SomeStruct.byReference[] structs = new SomeStruct.byReference[]{
new SomeStruct.byReference(123,"hey!",1.23),
new SomeStruct.byReference(456,"cool!",1.45),
new SomeStruct.byReference(789,"world!",1.67) }; JniTest.instance.printStructArray(structs, 3);
方法声明为:
void printStructArray(SomeStruct.byReference[] someStructarray, int num);
这给出了"0"作为函数的输出,尽管好处是它不会崩溃,但它也没有给出正确的行为。
思潮?
传递 Structure.ByReference 数组就足够了; 数组的地址被传递给本机代码。 JNA 会自动为指针数组分配空间,指针数组在函数调用后超出范围。
PointerByReference 旨在通过引用传递指针值(即被调用方可以更改该值)。 在这种情况下是不合适的。
我刚刚找到了一个非常好的解决方案,那就是使用 BridJ 而不是 JNA。 也许有一种方法可以让JNA工作,但这似乎并不明显。 BridJ 非常易于使用:
声明:
public static native void printStructArray(Pointer<Pointer<SomeStruct > > someStruct, int arraySize);
用法:
Pointer<Pointer<SomeStruct>> pointers = Pointer.allocatePointers(SomeStruct.class, 3);
pointers.set(0, Pointer.pointerTo( new SomeStruct().aDouble(1.58).aLong(5432).aString(Pointer.pointerToCString("Wheee!")) ) );
pointers.set(1, Pointer.pointerTo( new SomeStruct().aDouble(1.58).aLong(5432).aString(Pointer.pointerToCString("Wheee!")) ) );
pointers.set(2, Pointer.pointerTo( new SomeStruct().aDouble(1.58).aLong(5432).aString(Pointer.pointerToCString("Wheee!")) ) );
JnitestLibrary.printStructArray(pointers, 3 );
似乎它们不支持按值划分的结构,但是我当前的界面中没有任何按值划分的结构,所以现在对我来说这不是问题。 显然性能还可以,但我还没有亲自测试性能。
请注意,我仍然对 JNA 解决方案持开放态度,并且会勾选任何可以给我解决问题的 JNA 解决方案的人。
C还是C++?
如果是 C,为什么不简单地使用 calloc/malloc 为结构分配双指针,如下所示?
somestruct = (SomeStruct **)calloc(arraySize, sizeof(SomeStruct *));
for (i = 0; i < arraySize; i++)
somestruct[i] = (SomeStruct *)calloc(1, sizeof(SomeStruct));
现在,您可以根据需要填充结构。
最后,我从未找到可行的解决方案。 我所做的是通过用 C 编写一个包装器接口来解决问题,该接口为 Java 提供了一个非常简单的接口,然后很容易链接到使用 JNA,而无需 Pointer 等。 这工作得很好,并且比尝试让指针工作要少。
所以,我的界面看起来像:
int createHandle()
void doSomething( int handle )
void releaseHandle( int handle)
就时间而言,与尝试创建一些超级复杂的 jna 实现以直接连接到底层 c 接口相比,让这项工作工作似乎要少得多。
另一个优点是这意味着很容易连接到 c++ 库,因为这样,c++ 接口被 c 接口包装,很容易连接。
- 添加到数组指针
- C++语法差异:二维和一维数组(指针算术)
- 数组指针表示法C++(移动数组时)
- 复制后删除原始数组指针将前 3 个字节设置为 0
- C++访问指向结构的指针中的类数组指针
- C++编译时使用 constexpr 字符数组指针分配静态数组?
- std::flush可以用于将对象指针转换为其封闭数组指针吗
- 创建<int>对整数数组指针的矢量引用 (C++)
- 将 2D 数组指针传递给 C++ 中的函数
- 创建指针是否超过非数组指针的末尾,而不是从 C++17 中的一元运算符和未定义的行为派生?
- 队列数组指针 (C++)
- C++数组指针上的删除操作
- 对于循环不循环和检测字符数组 [指针和字符数组]
- 如何初始化数组指针对象
- 如何正确传递 2D 数组指针作为参数
- 从数组指针中获取怪异的数字
- 初始化std :: unique_ptr作为原始数组指针的初始化
- 将结构数组指针从C#传递到C
- STD :: Sort将数组指针设置为NULL
- C++数组指针错误无法将“int*”转换为“int**”