JNA 二维数组
JNA 2 Dimensional Arrays
JNA 二维数组
我的C函数是
void func(void** bufs, int numBufs);
C 代码需要一个指向字节数组的指针数组。 func()
知道每个字节数组的长度并用数据填充它们。
这个的 JNA 签名是什么?
这个看似简单的问题折腾了两天也没有破解
在 Java 方面,我有 DirectBuffer bufs[]
,目的是让 C 函数用数据填充 bufs[]
。
我曾期望我可以将 JNA 签名声明为
public static native boolean func(Pointer[] bufs, int numBufs);
然后构建一个 Java 指针数组,每个指针是 new Pointer(db.address());
但是虽然我可以构造 java 指针数组,但我得到了错误:
java.lang.IllegalArgumentException: class [Lcom.sun.jna.Pointer; is not a supported argument type (in method func in class SomeLib)
我已经尝试了很长时间,但一无所获。我查看了 StackOver 流程上的所有 JNA 示例,但 none 非常合适。
我正在通过 Maven 使用 JNA
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.3.1</version>
</dependency>
感谢任何帮助。
你很接近。不幸的是,non-primitive 数组到 C 的映射只有一种方式......您可以将检索到的内存映射到 Java 数组,但不能将 Java 数组发送到 C(基元除外) .
此限制的原因是在 C 中,数组是连续的内存块。要访问数组的第二个元素,只需偏移等于第一个元素大小的字节数。但是传递给 C 函数的参数只是一个指向数组开头的指针。
所以你的 func()
映射应该使用 Pointer
作为数组参数。
您没有描述如何构建 Pointer[]
数组,但是使用 new Pointer()
调用分配每个数组将产生分散在本机内存中而不是连续的指针。
基本上有两种方法可以确保您拥有连续的内存,具体取决于您想要的抽象级别。
一种 low-level 方法是创建一个 Memory
对象,为您的 Pointer
数组(可能 new Memory(Native.POINTER_SIZE * numBufs)
)分配足够的空间,然后使用 setPointer()
使用 Native.POINTER_SIZE
偏移量的适当倍数将数组映射到 Memory
对象。然后将 Memory
对象传递给 C 函数。
更高级别的方法是将指针包装在 JNA Structure
中,使用 Structure.toArray()
方法为您进行连续的数组分配。所以你可以这样:
public class Foo extends Structure {
public Pointer bar;
}
然后创建数组:
Foo[] array = (Foo[]) new Foo().toArray(numBufs);
此时您有一个(连续的)本机内存数组映射到 JNA 的 Pointer
类型。现在您只需将这些 Pointers-to-pointers 分配给附加到您的数据的指针:
for (int i = 0; i < numBufs; i++) {
// Assign Pointer to corresponding DirectBuffer
array[i].bar = bufs[i];
}
那么你应该能够通过传递第一个元素的指针来将数组传递给 C:
func(array[0].bar, numBufs);
// or equivalently
func(array[0].getPointer(), numBufs);
JNA 二维数组
我的C函数是
void func(void** bufs, int numBufs);
C 代码需要一个指向字节数组的指针数组。 func()
知道每个字节数组的长度并用数据填充它们。
这个的 JNA 签名是什么?
这个看似简单的问题折腾了两天也没有破解
在 Java 方面,我有 DirectBuffer bufs[]
,目的是让 C 函数用数据填充 bufs[]
。
我曾期望我可以将 JNA 签名声明为
public static native boolean func(Pointer[] bufs, int numBufs);
然后构建一个 Java 指针数组,每个指针是 new Pointer(db.address());
但是虽然我可以构造 java 指针数组,但我得到了错误:
java.lang.IllegalArgumentException: class [Lcom.sun.jna.Pointer; is not a supported argument type (in method func in class SomeLib)
我已经尝试了很长时间,但一无所获。我查看了 StackOver 流程上的所有 JNA 示例,但 none 非常合适。
我正在通过 Maven 使用 JNA
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.3.1</version>
</dependency>
感谢任何帮助。
你很接近。不幸的是,non-primitive 数组到 C 的映射只有一种方式......您可以将检索到的内存映射到 Java 数组,但不能将 Java 数组发送到 C(基元除外) .
此限制的原因是在 C 中,数组是连续的内存块。要访问数组的第二个元素,只需偏移等于第一个元素大小的字节数。但是传递给 C 函数的参数只是一个指向数组开头的指针。
所以你的 func()
映射应该使用 Pointer
作为数组参数。
您没有描述如何构建 Pointer[]
数组,但是使用 new Pointer()
调用分配每个数组将产生分散在本机内存中而不是连续的指针。
基本上有两种方法可以确保您拥有连续的内存,具体取决于您想要的抽象级别。
一种 low-level 方法是创建一个 Memory
对象,为您的 Pointer
数组(可能 new Memory(Native.POINTER_SIZE * numBufs)
)分配足够的空间,然后使用 setPointer()
使用 Native.POINTER_SIZE
偏移量的适当倍数将数组映射到 Memory
对象。然后将 Memory
对象传递给 C 函数。
更高级别的方法是将指针包装在 JNA Structure
中,使用 Structure.toArray()
方法为您进行连续的数组分配。所以你可以这样:
public class Foo extends Structure {
public Pointer bar;
}
然后创建数组:
Foo[] array = (Foo[]) new Foo().toArray(numBufs);
此时您有一个(连续的)本机内存数组映射到 JNA 的 Pointer
类型。现在您只需将这些 Pointers-to-pointers 分配给附加到您的数据的指针:
for (int i = 0; i < numBufs; i++) {
// Assign Pointer to corresponding DirectBuffer
array[i].bar = bufs[i];
}
那么你应该能够通过传递第一个元素的指针来将数组传递给 C:
func(array[0].bar, numBufs);
// or equivalently
func(array[0].getPointer(), numBufs);