2

私は JNA を使用して、Java から私が作成した小さな C ライブラリへのネイティブ関数呼び出しを比較的成功させてきました。構造体のマッピング、メモリ管理、および参照渡しのトリックを理解すれば、構造体またはポインターを一方から他方に渡すことがうまく機能します。

私は今、Java から C に構造体の配列を渡そうとしています。構造体の C コードは次のとおりです。

typedef struct key {
  int length;
  void *data;
} key_t;

私はJavaで一致する定義を持っています:

public class Key extends Structure {

  public int length;
  public Pointer data;

  public Key() {
    this.setFieldOrder(new String[] {"length", "data"});
  }

  public void setAsLong(long value) {
    this.length = 8;
    this.data = new Memory(this.length);
    this.data.setLong(0, value);
  }

  public long longValue() {
    return this.data != null ? this.data.getLong(0) : Long.MIN_VALUE;
  }
};

ドキュメントとオンラインで読んだ内容を理解していれば、Java 側で次の手順を実行して、配列を連続したメモリ セクションとして作成する必要があります。

Key[] keys = new Key().toArray(2);
for (int i=0; i<2; i++) {
  k.setAsLong(42+i);
}

ここまでは順調ですね。Keyを使用してJavaの各構造のコンテンツをダンプするとStructure.toString()、期待どおりにすべてがここにあります。KeyJava から C に1 つの構造体を渡すと、long 値として設定したり、キーのコンテンツにメモリを割り当てたりするコードが正常に機能することに注意してください。配列の要素:

instance.foo(keys[0].getPointer(), keys.length);

私のC関数はもちろん次のように定義されています:

void foo(key_t *keys, size_t count) {
  ...;
}

配列は正しくそこに到達しkeysます。C 側のポインターkeys[0].getPointer()は Java と同じアドレスを持ちますが、残念ながら配列内の各構造体のメンバーは、0/NULLGDB で指摘されているように、次のようになります。

(gdb) print keys
$1 = (key_t *) 0x7fd7e82389e0
(gdb) print keys[0]
$2 = {length = 0, data = 0x0}

この時点で、私は正直なところ、何が起こっているのかわかりません。先ほど言ったように、構造体を 1 つだけ渡せば問題なく動作しますが、ここでは無理です。私が見ることができる唯一の違いは、Pointer代わりに使用するJavaネイティブメソッドシグネチャですKey[]が、配列を使用すると、次のようになります。

IllegalArgumentException: [Lfoo.bar.Key; is not a supported argument type (in method foo ...

ありがとう

4

1 に答える 1

1

値を渡すPointer場合、JNAは、実際にStructureまたはそれらの配列を渡していることを認識しません。ネイティブ呼び出しの Structure.write()前後に確実に呼び出すのはあなた次第です。Structure.read()

Structureaまたはを渡すStructure[]と、JNAが自動的に同期を処理します。の場合Structure、JNAは内部簿記を使用して、渡す構造が構造の配列の先頭にあるかどうかを判断します。

于 2012-10-12T20:10:25.087 に答える