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