Когда я пытаюсь получить возвращаемое значение структуры в 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(structLayout, ADDRESS, JAVA_LONG)
(при условии, что ваш родной long
— 64 бита). Кроме того, C++ ABI не поддерживается. Связывание с функциями C++ может работать, но лучше указать связывание C с помощью extern "C"
(а затем следить за предупреждениями о несовместимом ABI).
Большое спасибо за Вашу помощь. Я утвердил свой код и внес необходимые изменения согласно вашим инструкциям. Я добавил свой метод модификации в описание, со мной что-то не так?
К счастью, с помощью Хольгера и Йорна Верне я модифицировал код и успешно его запустил. Внесены следующие изменения
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) }" );
}
Ваш
FunctionDescriptor.of(ADDRESS, ADDRESS, JAVA_LONG)
неправильный. Нативная функция возвращает не адрес, а саму точку. Обратите внимание, что «адрес», который вы пытаетесь разыменовать, т. е.38654705673
, в точности равен9L << 32 | 9L
, другими словами, ожидаемой максимальной точке, но интерпретированной неправильно.