Как получить возвращаемое значение структуры C++ из Java с помощью API внешних функций и памяти

Когда я пытаюсь получить возвращаемое значение структуры в C++, я не могу разрешить значение в структуре.

Это моя структура.

struct Point {
    int x;
    int y;
};

Это мой метод C++

Point test_point(Point points[],long count)
{
    if (count <= 0) {
        // Return a default Point with x and y set to 0
        Point defaultPoint = { 0, 0 };
        return defaultPoint;
    }

    Point maxPoint = points[0];
    int maxSum = maxPoint.x + maxPoint.y;

    for (int i = 1; i < count; ++i) {
        int currentSum = points[i].x + points[i].y;
        if (currentSum > maxSum) {
            maxSum = currentSum;
            maxPoint = points[i];
        }
    }

    int x = maxPoint.x;
    int y = maxPoint.y;
    std::cout << "x = " << x << ", y = " << y << std::endl;
    return maxPoint;
}

Это мой метод Java

public static void dereferenceSegmentsStruct() throws Throwable {
    Linker linker = Linker.nativeLinker();
    SymbolLookup symbolLookup = SymbolLookup.loaderLookup();
    MethodHandle test_point = linker.downcallHandle(
            symbolLookup.find("test_point").orElseThrow(),
            FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_LONG)
    );

    StructLayout structLayout = MemoryLayout.structLayout(
            JAVA_INT.withName("x"),
            JAVA_INT.withName("y"));

    SequenceLayout ptsLayout = MemoryLayout.sequenceLayout(10, structLayout);

    VarHandle xHandle    // (MemorySegment, long) -> int
            = ptsLayout.varHandle(PathElement.sequenceElement(),
            PathElement.groupElement("x"));
    VarHandle yHandle    // (MemorySegment, long) -> int
            = ptsLayout.varHandle(PathElement.sequenceElement(),
            PathElement.groupElement("y"));

    MemorySegment segment = Arena.ofAuto().allocate(ptsLayout);
    for (int i = 0; i < ptsLayout.elementCount(); i++) {
        xHandle.set(segment,
                /* index */ (long) i,
                /* value to write */ i); // x
        yHandle.set(segment,
                /* index */ (long) i,
                /* value to write */ i); // y
    }

    MemorySegment result = (MemorySegment) test_point.invoke(segment, ptsLayout.elementCount());
    result = result.reinterpret(structLayout.byteSize());
    System.out.println(result.getAtIndex(JAVA_INT, 0));
}

Я вижу нулевую длину и пытаюсь использовать метод для изменения нулевой длины.

изображение

Я до сих пор не могу его получить, выдает следующую ошибку.

Exception in thread "main" java.lang.IllegalArgumentException: Misaligned access at address: 38654705673
    at java.base/java.lang.invoke.VarHandleSegmentViewBase.newIllegalArgumentExceptionForMisalignedAccess(VarHandleSegmentViewBase.java:57)
    at java.base/java.lang.invoke.VarHandleSegmentAsInts.offsetNoVMAlignCheck(VarHandleSegmentAsInts.java:100)
    at java.base/java.lang.invoke.VarHandleSegmentAsInts.get(VarHandleSegmentAsInts.java:111)
    at java.base/java.lang.foreign.MemorySegment.getAtIndex(MemorySegment.java:1921)
    at org.example/org.example.TestNative.dereferenceSegmentsStruct(TestNative.java:109)
    at org.example/org.example.TestNative.main(TestNative.java:33)

Что мне нужно сделать, чтобы прочитать x и y точки, возвращенной в C++?

Ваш FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_LONG) неправильный. Нативная функция возвращает не адрес, а саму точку. Обратите внимание, что «адрес», который вы пытаетесь разыменовать, т. е. 38654705673, в точности равен 9L << 32 | 9L, другими словами, ожидаемой максимальной точке, но интерпретированной неправильно.

Holger 10.10.2023 13:11

Как говорит Хольгер, дескриптор функции здесь неверен, он должен быть FunctionDescriptor.of(structLayout, ADDRESS, JAVA_LONG) (при условии, что ваш родной long — 64 бита). Кроме того, C++ ABI не поддерживается. Связывание с функциями C++ может работать, но лучше указать связывание C с помощью extern "C" (а затем следить за предупреждениями о несовместимом ABI).

Jorn Vernee 10.10.2023 22:00

Большое спасибо за Вашу помощь. Я утвердил свой код и внес необходимые изменения согласно вашим инструкциям. Я добавил свой метод модификации в описание, со мной что-то не так?

jdragon 11.10.2023 06:33
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
3
98
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

К счастью, с помощью Хольгера и Йорна Верне я модифицировал код и успешно его запустил. Внесены следующие изменения

extern "C" MATHLIBRARY_API Point test_point(Point points[], long count);
public static void dereferenceSegmentsStruct() throws Throwable {
    StructLayout structLayout = MemoryLayout.structLayout(
            JAVA_INT.withName("x"),
            JAVA_INT.withName("y"));

    MethodHandle test_point = linker.downcallHandle(
            symbolLookup.find("test_point").orElseThrow(),
            FunctionDescriptor.of(structLayout, ADDRESS, JAVA_LONG)
    );

    SequenceLayout ptsLayout = MemoryLayout.sequenceLayout(10, structLayout);

    VarHandle xHandle    // (MemorySegment, long) -> int
            = ptsLayout.varHandle(PathElement.sequenceElement(),
            PathElement.groupElement("x"));
    VarHandle yHandle    // (MemorySegment, long) -> int
            = ptsLayout.varHandle(PathElement.sequenceElement(),
            PathElement.groupElement("y"));

    MemorySegment segment = Arena.ofAuto().allocate(ptsLayout);
    for (int i = 0; i < ptsLayout.elementCount(); i++) {
        xHandle.set(segment,
                /* index */ (long) i,
                /* value to write */ i); // x
        yHandle.set(segment,
                /* index */ (long) i,
                /* value to write */ i); // y
    }
    SegmentAllocator allocator = SegmentAllocator.slicingAllocator(Arena.ofAuto().allocate(100));
    MemorySegment result = (MemorySegment) test_point.invoke(allocator, segment, ptsLayout.elementCount());
    System.out.println(result);
    result = result.reinterpret(structLayout.byteSize());
    VarHandle resultX    // (MemorySegment, long) -> int
            = structLayout.varHandle(PathElement.groupElement("x"));
    VarHandle resultY    // (MemorySegment, long) -> int
            = structLayout.varHandle(PathElement.groupElement("y"));
    System.out.println(StringTemplate.STR. "\{ resultX.get(result) }:\{ resultY.get(result) }" );
}

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