JNA IntByReference в API внешних функций и памяти Java

У меня есть собственная библиотека .so, которая имеет следующую функцию:

void foo(void* handle);

Это хорошо работает на C#:

[DllImport("library.so", CallingConvention = (CallingConvention) 3)]
private static extern void foo(ref IntPtr handle);

// ...

IntPtr handle = IntPtr.Zero;
foo(ref handle);

Однако я не могу реализовать это в Java 22 с помощью FFM API:

var LINKER = Linker.nativeLinker();
var SYM_LOOKUP = SymbolLookup.loaderLookup().or(LINKER.defaultLookup());
var FOO = LINKER.downcallHandle(SYM_LOOKUP.find("foo").orElseThrow(), FunctionDescriptor.ofVoid(ADDRESS));

var handle = Arena.global().allocate(ValueLayout.ADDRESS); // is this correct?
FOO.invokeExact(handle);

По какой-то причине я получаю std::bad_array_new_length в нативном коде (исходников нативной библиотеки, к сожалению, у меня нет).

В JNA есть com.sun.jna.ptr.IntByReference, есть ли что-то подобное в FFM API?

Что произойдет, если вы выделите JAVA_INT? Обратите внимание: ADDEESS будет иметь размер 8 байт на 64-битной JVM.

Slaw 20.08.2024 23:48

@Slaw Тем не менее, у меня та же ошибка.

Eng.Fouad 20.08.2024 23:55

@BasilBourque Java 22

Eng.Fouad 21.08.2024 00:33

Хм. Я не знаю C#, но эти вопросы и ответы предполагают, что вы были на правильном пути, используя ADDRESS. Хотя в принятом ответе также говорится, что IntPtr.Zero «фактически NULL (нулевой указатель)». Этот другой вопрос и ответ , кажется, согласен. Что произойдет, если вы передадите MemorySegment.NULL (вместо выделения собственного сегмента)?

Slaw 21.08.2024 01:25

Ваш код выглядит правильно (хотя вы можете использовать Linker.nativeLinker().canonicalLayouts().get("size_t") вместо ADDRESS). Но указатель, который вы передаете foo, указывает на неинициализированную память, тогда как в коде C# память инициализируется нулем. Как foo справится с этим, зависит от foo. Мы не можем вам многого сказать, не зная контракта foo. Возможно, вы захотите попробовать allocateFrom(ADDRESS, MemorySegment.NULL) вместо allocate.

Jorn Vernee 21.08.2024 04:19

В API FFM нет прямого эквивалента IntByReference. Все указатели представлены как MemorySegment, к которым не привязан тип.

Jorn Vernee 21.08.2024 04:22

Вам нужна выделенная память размером с указатель, чтобы где-то указывать на выделенную память размера int. Независимо от того, выделяете ли вы память целочисленного размера или вызываемый API, требуется дополнительная документация.

Daniel Widdis 21.08.2024 06:51
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
7
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел ошибку. На самом деле у меня было 2 собственных метода:

void initHandle(void* handle);
void useHandle(void* handle);

и мне нужно инициализировать дескриптор, а затем использовать его. Я делал это:

var handle = Arena.global().allocate(ValueLayout.ADDRESS);
INIT_HANDLE.invokeExact(handle);
USE_HANDLE.invokeExact(handle);

Оказывается, во второй функции мне пришлось передать дескриптор по-другому:

var handle = Arena.global().allocate(ValueLayout.ADDRESS);
INIT_HANDLE.invokeExact(handle);
USE_HANDLE.invokeExact(handle.get(ValueLayout.ADDRESS, 0));

Другие вопросы по теме