如何使用二维指针通过 JNA 调用 C 函数?
How to call C function through JNA with 2d pointer?
这是我的 C 函数的签名:
typedef struct myitem_s {
int a;
int b;
} myitem_t;
int get_items(myitem_t** items);
在C程序中的用法是::
myitem_t* items = NULL;
int n = = get_items(&items);
for (int i = 0; i < n; ++i) {
myitem_t* item = &items[i];
}
items
分配在get_items()
函数中,包含一个或多个myitem_t
个元素。
从 Java 代码我已经成功地做到了这一点:
Memory itemsPtr = new Memory(Native.POINTER_SIZE);
Pointer p = itemsPtr.getPointer(0);
int n = CLibrary.INSTANCE.get_items(p);
n
值有效,itemsPtr
已更新,所以我建议值也不错。现在我不知道如何使用它。还有其他方法吗?
您的代码有效,但是当 JNA 具有一些更高级别的构造时,您使用了很多较低级别的函数。
首先,Cstruct
可以用JNAStructure
表示。
@FieldOrder({ "a", "b" })
class MyitemT extends Structure {
public int a;
public int b;
}
由于本机代码正在处理内存分配,您所需要的只是指向它的指针。您可能需要 PointerByReference
.
而不是 pointer-sized 内存分配
PointerByReference pbr = new PointerByReference();
你想要的关键方法是getPointer()
(指向指针的指针)和getValue()
(pointed-to值)。
鉴于上述情况,将 pointer-to-the-pointer 传递给方法,该方法将分配内存并填充值。
使用您已有的映射(未显示但推断):
int n = CLibrary.INSTANCE.get_items(pbr.getPointer());
但是,您实际上应该映射 get_items()
以获取 PointerByReference
参数,然后您可以直接传递 items
。
此时,items.getValue()
是结构数组开头的 Pointer
。根据结构的大小 (item.size()
),其他项目将位于指针值的偏移量处。有多种方法可以做到这一点。
在你的情况下,因为你知道你只有一对整数,你可以跳过整个“结构”部分,只使用 items.getValue().getInt(0)
和 items.getValue().getInt(4)
作为第一对;第二对是 8 和 12,等等。但更好的是,只需 items.getValue().getIntArray(0,n*2);
获取一个整数数组,只需将它们成对取出即可。
但这利用了内部细节。最 JNA-ish 的选择可能是使用 Structure.toArray()
创建一个 MyitemT
结构数组。如果包含指针构造函数并使用该指针创建初始结构,Structure.toArray()
将使用该现有映射。然后你可以 read()
进入你的数组:
MyItemT item = new MyItemT(pbr.getValue());
MyItemT[] items = (MyItemT[]) item.toArray(n);
for (int i = 0; i < n; i++) {
items[i].read();
// now you can see items[i].a and items[i].b
}
不要忘记最终释放 native-allocated 内存,但是 API 告诉你这样做!
这是我的 C 函数的签名:
typedef struct myitem_s {
int a;
int b;
} myitem_t;
int get_items(myitem_t** items);
在C程序中的用法是::
myitem_t* items = NULL;
int n = = get_items(&items);
for (int i = 0; i < n; ++i) {
myitem_t* item = &items[i];
}
items
分配在get_items()
函数中,包含一个或多个myitem_t
个元素。
从 Java 代码我已经成功地做到了这一点:
Memory itemsPtr = new Memory(Native.POINTER_SIZE);
Pointer p = itemsPtr.getPointer(0);
int n = CLibrary.INSTANCE.get_items(p);
n
值有效,itemsPtr
已更新,所以我建议值也不错。现在我不知道如何使用它。还有其他方法吗?
您的代码有效,但是当 JNA 具有一些更高级别的构造时,您使用了很多较低级别的函数。
首先,Cstruct
可以用JNAStructure
表示。
@FieldOrder({ "a", "b" })
class MyitemT extends Structure {
public int a;
public int b;
}
由于本机代码正在处理内存分配,您所需要的只是指向它的指针。您可能需要 PointerByReference
.
PointerByReference pbr = new PointerByReference();
你想要的关键方法是getPointer()
(指向指针的指针)和getValue()
(pointed-to值)。
鉴于上述情况,将 pointer-to-the-pointer 传递给方法,该方法将分配内存并填充值。
使用您已有的映射(未显示但推断):
int n = CLibrary.INSTANCE.get_items(pbr.getPointer());
但是,您实际上应该映射 get_items()
以获取 PointerByReference
参数,然后您可以直接传递 items
。
此时,items.getValue()
是结构数组开头的 Pointer
。根据结构的大小 (item.size()
),其他项目将位于指针值的偏移量处。有多种方法可以做到这一点。
在你的情况下,因为你知道你只有一对整数,你可以跳过整个“结构”部分,只使用 items.getValue().getInt(0)
和 items.getValue().getInt(4)
作为第一对;第二对是 8 和 12,等等。但更好的是,只需 items.getValue().getIntArray(0,n*2);
获取一个整数数组,只需将它们成对取出即可。
但这利用了内部细节。最 JNA-ish 的选择可能是使用 Structure.toArray()
创建一个 MyitemT
结构数组。如果包含指针构造函数并使用该指针创建初始结构,Structure.toArray()
将使用该现有映射。然后你可以 read()
进入你的数组:
MyItemT item = new MyItemT(pbr.getValue());
MyItemT[] items = (MyItemT[]) item.toArray(n);
for (int i = 0; i < n; i++) {
items[i].read();
// now you can see items[i].a and items[i].b
}
不要忘记最终释放 native-allocated 内存,但是 API 告诉你这样做!