JNA: получить значение из указателя на указатель на структуру - PullRequest
1 голос
/ 14 июля 2020

У меня проблемы с JNA по поводу проблемы с указателем на указатель.

Пример структуры:

typedef struct _A {
    unsigned int num;
    struct _A *next;
} A, *PA;

C метод:

void test(PA *a) {
    PA current = (PA) malloc(sizeof(A));
    current->num = 123321;

    PA next = (PA) malloc(sizeof(A));
    next->num = 456;
    current->next = next;

    *a = current;
}

Простой тест в C:

int main() {
    PA a = NULL;
    test(&a);

    printf("%d\n", a->num);
    printf("%d", a->next->num);
}

Код JNA

public interface DLLLibrary extends Library {
    ......

    void test(PointerByReference a);
}

public class A extends Structure {
    public int num;
    public ByReference next;
    public A() {
        super();
    }
    protected List<String> getFieldOrder() {
        return Arrays.asList("num", "next");
    }

    public A(Pointer peer) {
        super(peer);
    }
    public static class ByReference extends A implements Structure.ByReference { }
    public static class ByValue extends A implements Structure.ByValue { }
}

Наконец, я пытаюсь получить поля структуры, которые были обновлены в C, но получаю «Недопустимый доступ к памяти. "

public static void main(String[] args) {
    PointerByReference pointer = new PointerByReference();
    DLLLibrary.INSTANCE.test(pointer);

    assert pointer.getValue().getInt(0) == 123321; //this works
    A a = new A(pointer.getValue());
    //assert a.next.num == 456;  //excepted action
    a.read(); //java.lang.Error: Invalid memory access
}

Были ли ошибки в моих шагах?

1 Ответ

0 голосов
/ 14 июля 2020

Когда вы получаете сообщение об ошибке «Недопустимый доступ к памяти», вы должны начать смотреть, когда выделение собственной памяти выполнено. Обычно API документирует это (и говорит вам, как его освободить), а когда нет, вы знаете, что это ваша ответственность. В этом случае вы можете видеть в опубликованном вами коде C, распределение выполняется внутри метода тестирования:

PA current = (PA) malloc(sizeof(A));

и

PA next = (PA) malloc(sizeof(A));

Проблема в том, что сторона Java не знает об этом распределении, поэтому вам придется сделать это вручную.

Ваше отображение функции с использованием PointerByReference выглядит нормально. Хотя вы можете использовать getInt(0) при возврате, вам, вероятно, будет лучше на этом этапе просто создать экземпляр структуры A из возвращенного указателя, как вы это сделали:

A a = new A(pointer.getValue());

Затем a.num должен быть ваш ожидаемый 123321. Затем вы должны взять возвращенный указатель (на ссылку, выделенную в собственном коде) и использовать его для создания другой Java -сторонней структуры:

A b = new A(a.next);

(вы можете захотеть просто используйте Pointer в структуре, чтобы упростить эту часть. Если вы используете ByReference или A.ByReference, тогда используйте getPointer() в этой части.)

На этом этапе я считаю b.num должен дать вам 456.

...