【问题标题】:JNA 2 Dimensional ArraysJNA 2 维数组
【发布时间】:2019-06-09 14:36:47
【问题描述】:

JNA 二维数组

我的 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


    【解决方案1】:

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

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

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

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

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

    一种低级方法是创建一个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 类型。现在您只需将这些指向指针的指针分配给附加到数据的指针:

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

    【讨论】:

    • 非常感谢您提供如此出色的解释和详细的代码。现在就试一试。
    • 刚刚试了一下,效果不错!我在第一次尝试时使用了低级版本,但将探索扩展结构版本,看看哪个看起来更优雅。我确实发现 Pointer.SIZE 不存在,目前使用的常量为 8,它假定是 64 位平台,因此这可能足以使用您说明的替代方法。所以再次非常感谢。在我看来,这肯定是 JNA 用户非常常见的情况。有什么办法可以将其添加到 JNA 站点作为示例?
    • 糟糕,Pointer.SIZE 在 4.x 版本中,但在 5.x 中被 Native.POINTER_SIZE 替换,以防止在从多个线程初始化 JNA 时出现类加载死锁。
    • 至于添加到 JNA 站点,我建议您在 JNA 邮件列表中发布您的问题,并询问当前文档是否处理它。完全有可能有比我发布的解决方案更好的解决方案。
    • 我的缓冲区是由ByteBuffer.allocateDirect() 创建的 DirectBuffers 我通过将ByteBuffer 转换为DirectBuffer 来分配指针,这样我就可以得到``` DirectBuffer db = (DirectBuffer) myBuffer; ptr.setPointer(i * Native.POINTER_SIZE, new Pointer(db.address())); ``` 但我现在注意到 sun.nio.ch.DirectBuffer 是一个内部专有 API。有没有办法避免为此使用内部专有 API?
    猜你喜欢
    • 1970-01-01
    • 2016-12-30
    • 2014-11-02
    • 1970-01-01
    • 2013-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    相关资源
    最近更新 更多