2016-03-22 21 views
5

コンピュータのRS485インターフェイス上のデバイスと通信するためにJNAを使用し始めています。幸い私には、すぐに良い結果が出ました。しかし今、私は簡単な問題で立ち往生しています。私が使用するライブラリは、structのポインタへのポインタを受け取ります。実際の署名は、ライブラリーは、最後のポインタがNULLポインタであることを期待する最初のパラメータの大きさを示すために、今JNA:structポインタをNULLに設定する

func(Struct1 **, Struct2 **, Struct3 *, Struct4 *, long)

あります。これは失敗するものです。

Struct1.ByReference[] s = (Struct1.ByReference[]) new Struct1.ByReference().toArray(size); 
    int pos = 0; 

    // ... 
    // for loop to set the s[pos] struture values 
    for(pos = 0; pos < size - 1; pos++) 
    // ... 

    // Now set the last array element to a null pointer to indicate end-of-list 
    s[pos].getPointer().setPointer(0, null);// Following does not work: results in zero memoried structure 
    s[pos] = null; // Following does not work wither: NullPointerException at com.sun.jna.Structure.autoWrite 

EDIT 1

s[pos] = new Struct1.ByReference(Pointer.NULL); // results in zero memoried structure as well 

EDIT 2

technomageの質問によると:コードに続いて、私がこれまで試したものです。私はCのコードを書くとしたら、それはおそらく、そのようなことになります。

Struct1 **s = malloc(n * sizeof(Struct1*)); 

for(int i=0; i<n; i++) 
{ 
    if(i == n -1) 
    { 
     s[i] = NULL; 
    } 
    else 
    { 
     s[i] = malloc(sizeof(Struct1)); 
     s[i].bla = value; 
     .... 
    } 
} 

をしかし、警告が表示さ:私はC/C++で非常に熟練していないです。私はJavaを私のドメインと考えています。

誰も同じような問題がありましたか?たぶん私は木の木を見ていないだけです...

ありがとうございます。

+0

ネイティブ用のサンプルを含めてください。ポインタのバリエーションの関数宣言は、そのコンテキストなしではあいまいである可能性があります。つまり、配列へのポインタ、単一のポインタ値へのポインタ、またはいくつかの他のバリエーションを区別する方法はありません。 – technomage

+0

「使用例」とはどういう意味ですか?このライブラリは、オープンソースのリアルタイムオペレーティングシステムであるFreeRTOSを実行する組み込み機器のコードから採用されました。ライブラリのメソッドをエクスポートするヘッダーファイルとは別にネイティブコードがありません。 –

+0

あなたが望むやり方でライブラリにアクセスする 'C'のコードを書こうとすると、どのように見えますか? – technomage

答えて

0

JNAの構造体はポインタなので、ここで実際に必要なのは、構造体へのポインタ(PointerByReference - あなたの場合はそれらの配列)です。上記のコードの例を考えると

は、あなたがnより1少ない構造、あなたの配列を作成します:

Struct1[] struct1Array = new Struct1[n-1]; 

これはのみのアレイのためのJavaのメモリを割り当てます。

次はインスタンス化し、ネイティブメモリに加えた変更を記述します:

for (int i = 0; i < n-1; i++) { 
    struct1Array[i] = new Struct1(); 
    struct1Array[i].bla = value; 
    struct1Array[i].write(); 
} 

new Struct1()は、これらの構造のためのネイティブ側のメモリを割り当てます。これを行うにはStructure.toArray()メソッドを使用することもできます。私は意図的に、何が起こっているのかを明確にしようとするために、もう少しマニュアルと低レベルを行っています。

次に、対応するPointerByReference配列を作成して、これらの構造体へのポインタを保持します。

PointerByReference[] pbrArray = new PointerByReference[n]; 

この場合も、これはJava側の割り当てにすぎません。

for (int i = 0; i < n-1; i++) { 
    pbrArray[i] = new PointerByReference(struct1Array[i].getPointer()); 
} 
pbrArray[n - 1] = new PointerByReference(Pointer.NULL); 
ここ

new PointerByReference()はあなたが割り当てられたネイティブ側の構造を指すポインタ自体のネイティブ側のメモリを割り当て:そして、あなたはStructure.getPointer()方法から得られた構造体へのポインタへのポインタ、とそれを埋めます早く

私はあなたの最初の質問をどのように理解してから、このPointerByReference配列を関数に渡します。おそらくあなたの構造が更新されます。

このように2つの配列を作成したので、配列のインデックスで対応を追跡できます。構造体配列を反復処理し、ネイティブメモリをJava側の構造体にread()する必要があるかもしれません。通常、構造体がautowriteとautoreadメソッドに渡されたときに構造体を直接操作するときに、PointerByReferenceを使用して構造体を間接参照すると、JNAはあまりフレンドリーではありません。

対応するインデックスで2つの配列をトラッキングする代わりに、初期構造の割り当てを "忘れ"て、後で配列のPointerByReference.getValue()メソッドを使用して構造体のメモリへのポインタを復元し、そのポインタをそのコンストラクタで使用する新しい構造体(例えばnew Struct1(pbr.getValue())、そのポインタでsuper()を呼び出す)。

関連する問題