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);
}

到现在为止还挺好。如果我使用 转储KeyJava 中每个结构的内容Structure.toString(),那么一切都在此处。请注意,当我将单个Key结构从 Java 传递到 C 时,关于设置为长值、为键的内容分配内存等的代码工作正常。所以在这里我通过使用指向第一个的指针将数组传递给我的本机函数数组元素:

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

我的 C 函数当然是这样定义的:

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

数组正确到达那里:keysC端的指针与Java中的地址相同keys[0].getPointer(),但不幸的是,数组中每个结构的成员都是0/NULL,正如GDB所指出的那样:

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

在这一点上,老实说,我不知道发生了什么。正如我所说,如果我只通过一个结构,它可以正常工作,但这里没有办法。我能看到的唯一区别是 Java 本机方法签名,它使用Pointer而不是,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()之后调用。

如果您传递 aStructureStructure[],则 JNA 将自动处理同步。在 的情况下Structure,JNA 使用内部簿记来确定您传递的结构是否位于结构数组的开头。

于 2012-10-12T20:10:25.087 回答