3

我正在使用 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”作为函数的输出,虽然好处是它不会崩溃,但它也没有给出正确的行为。

想法?

4

4 回答 4

2

传递您的 Structure.ByReference 数组就足够了;数组的地址被传递给本机代码。JNA 自动为指针数组分配空间,该指针数组在函数调用后超出范围。

PointerByReference 旨在通过引用传递指针值(即被调用者可以更改值)。在这种情况下是不合适的。

于 2012-06-19T03:07:46.700 回答
2

我刚刚找到了一个效果很好的解决方案,即使用 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 解决方案的人。

于 2012-06-19T03:21:03.730 回答
0

这是 C 还是 C++?

如果是 C,为什么不简单地使用 calloc/malloc 为结构分配双指针,如下所示?

somestruct = (SomeStruct **)calloc(arraySize, sizeof(SomeStruct *));

for (i = 0; i < arraySize; i++)

    somestruct[i] = (SomeStruct *)calloc(1, sizeof(SomeStruct));

现在,您可以根据需要填充结构。

于 2012-06-19T01:08:42.010 回答
0

最后,我从来没有找到一个可行的解决方案。我所做的是通过在 C 中编写一个包装器接口来解决问题,它为 Java 提供了一个非常简单的接口,然后很容易使用 JNA 链接到它,而无需指针等。这工作得很好,而且比试图让 Pointer 工作更省力。

所以,我的界面看起来像:

int createHandle()
void doSomething( int handle )
void releaseHandle( int handle)

就时间而言,似乎比尝试创建一些超级复杂的 jna 实现来直接连接到底层 c 接口所需的努力要少得多。

另一个优点是这意味着它很容易连接到 c++ 库,因为这样,c++ 接口由易于连接的 ac 接口包装。

于 2012-09-28T14:03:20.970 回答