首页 > 解决方案 > JNA 2 维数组

问题描述

JNA 2 维数组

我的 C 函数是

    void func(void** bufs, int numBufs);

Tye 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 flow 上的所有 JNA 示例,但没有一个完全适合。

我正在通过 Maven 使用 JNA

        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>5.3.1</version>
        </dependency>

任何帮助将不胜感激。

标签: jna

解决方案


你很近。不幸的是,非原始数组到 C 的映射只能以一种方式工作……您可以将检索到的内存映射到 Java 数组,但不能将 Java 数组发送到 C(原始数组除外)。

这种限制的原因是在 C 中,数组是连续的内存块。要访问数组的第二个元素,只需偏移等于第一个元素大小的字节数。但是传递给 C 函数的参数只是指向数组开头的指针。

所以你的映射func()应该使用Pointer数组参数。

您没有描述如何构造Pointer[]数组,但是通过调用分配每个数组new Pointer()会产生分散在本机内存中而不是连续的指针。

基本上有两种方法可以确保您拥有连续的内存,具体取决于您想要的抽象级别。

一种低级方法是创建一个对象,为您的数组(可能)Memory分配足够的空间,然后使用适当的偏移倍数将您的数组映射到该对象。然后将对象传递给 C 函数。Pointernew Memory(Native.POINTER_SIZE * numBufs)setPointer()Native.POINTER_SIZEMemoryMemory

更高级别的方法是将 Pointer 包装在 JNAStructure中,使用该Structure.toArray()方法为您进行连续数组分配。所以你可以有这个:

public class Foo extends Structure {
    public Pointer bar; 
}

然后创建数组:

Foo[] array = (Foo[]) new Foo().toArray(numBufs);

此时,您有一个(连续的)本机内存数组映射到 JNA 的Pointer类型。现在您只需将这些指向指针的指针分配给附加到数据的指针:

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

推荐阅读