当我try 在C++中获取 struct 返回值时,我无法解析 struct 中的值.

这就是我的 struct .

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

我看到零长度,我试着用一种方法来修改零长度.

image

我仍然不能得到它,它给出以下错误.

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)

我需要做什么来读取在C++中返回的Point的x和y?

推荐答案

幸运的是,在Holger和Jorn Vernee的帮助下,我修改了代码并成功地运行了它.进行了以下修改

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

Java相关问答推荐

Java JAR环境(JRE)是否支持模块?

Java自定义ThreadPool—暂停任务提交并取消当前排队任务

Java中是否有某种类型的池可以避免重复最近的算术运算?

Hibernate 6支持Joda DateTime吗?

JavaFX Maven Assembly插件一直打包到错误的JDK版本

使用PDFBox从PDF中删除图像

使用用户引入的参数生成人员数组

如何在一行中使用Dijkstra中的Java Stream

try 将JSON字符串响应从API转换为映射字符串、对象>;时出错

Spring安全令牌刷新和JWT签名与本地计算的签名不匹配

SpringBoot:在条件{Variable}.isBlank/{Variable}.isEmpty不起作用的情况下进行路径变量验证

从映射列表中检索所有键

try 使用预准备语句占位符获取信息时出现Try-With-Resources错误

如何在Java中使用正则表达式拆分字符串

使用MediaPlayer类在一段时间后停止播放音乐

我们可以在方法中声明接口吗?

如何使用外部函数从Java中获取C++ struct 的返回值&;内存API

在输入端没有可行的替代方案'; Select *';

使用DynamoDB增强客户端时未更新属性

Keycloak + Spring Boot 角色认证不起作用