JNA 2-мерные массивы - PullRequest
1 голос
/ 07 июня 2019

JNA 2-мерные массивы

Моя функция C имеет значение

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

Код C Tye ожидает массив указателей на массивы байтов.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)

Я долго экспериментировал и никуда не деться.Я рассмотрел все примеры JNA для потока StackOver, но ни один из них не совсем подходит.

Я использую JNA через Maven

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

Любая помощь с благодарностью.

1 Ответ

1 голос
/ 07 июня 2019

Ты рядом. К сожалению, отображение не примитивных массивов в 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);
...