3

Java から C ライブラリを呼び出すために JNA を使用しています。

私の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

JNAの代わりにBridJを使用するという、非常にうまく機能するソリューションを見つけました。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 でラッパー インターフェイスを作成することによる回避策でした。これは、Java への非常に単純なインターフェイスを提示し、ポインターなどを必要とせずに、JNA を使用してリンクするのが非常に簡単でした。これは非常にうまく機能し、Pointer を機能させようとするよりも労力がかかりませんでした。

したがって、私のインターフェースは次のようになりました。

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

基盤となる c インターフェイスに直接接続するための非常に複雑な jna 実装を作成しようとするよりも、時間の点でこれを機能させるのにかかる労力ははるかに少ないようです。

もう 1 つの利点は、c++ ライブラリに簡単に接続できるということです。これは、c++ インターフェースが ac インターフェースによってラップされているため、簡単に接続できるからです。

于 2012-09-28T14:03:20.970 に答える
0

これは C または C++ ですか?

C なら、単純に calloc/malloc を使用して、次のように構造体に double ポインターを割り当ててみませんか?

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 に答える