2012-03-13 58 views
0

进出口试图建立一个可以从Java经由JNA可以使用C++库。我正在做一些测试来返回一个Structs数组。我创建了以下结构:返回阵列的第一个结构是空的

C++:

namespace structures 
{ 
    typedef struct _Point { 
     int x, y; 
    } Point; 
} 

的Java:

public class Point extends Structure { 
    public Point() { 
    // required for toArray() 
    } 

    public Point(Pointer pointer) { 
    super(pointer); 
    } 

    public int x, y; 
} 

所以,我有一个C++方法返回点的数组:

extern "C" __declspec(dllexport) structures::Point* getPoints(){ 
    structures::Point *p; 
    p = (structures::Point *) malloc(4 * sizeof(structures::Point)); 
    p[0].x = 10; 
    p[0].y = 20; 
    p[1].x = 30; 
    p[1].y = 40; 
    p[2].x = 50; 
    p[2].y = 60; 
    p[3].x = 70; 
    p[3].y = 80; 
    return p ; 

而且在Java中,这是声明库访问接口:

public interface Multiplyt extends Library{ 
    Pointer getPoints(); 
} 

这是测试库中的代码:

Pointer pointer = test.getPoints(); 
Point point, points[]; 
point = new Point(pointer); 
points = (Point[]) point.toArray(4); 
System.out.println("0x:"+points[0].x + " 0y:" + points[0].y + " 1x:"+ points[1].x + " 1y:" + points[1].y); 
System.out.println("2x:"+points[2].x + " 2y:" + points[2].y + " 3x:"+points[3].x + " 3y:" + points[3].y); 

这些命令的输出是:

0x:0 0y:0 1x:30 1y:40 
2x:50 2y:60 3x:70 3y:80 

因此,大家可以看到,在位置点结构0有没有x或y的值(它有0和0,它应该是10和20)。这是为什么发生?我该如何纠正它?

回答

2

你的结构数据是未初始化的,因为你永远不会从一个指针值初始化结构之后调用Structure.read()。

JNA将在某些情况下隐含地调用Structure.read()为您,如前/原生函数调用后,或者扩展的单一结构成由相同的存储器支持的阵列时。然而,在后一种情况下,您的第一个元素是未初始化的,因为当您调用toArray()时,JNA会假定它已经被初始化。

当你声明你的函数返回一个结构,而不是一个指针,JNA可以猜测,它需要调用Structure.read()为您服务。

+0

谢谢。在调用数组之后调用“.read()”点也使得avobe代码有效。我还尝试在Java中声明接口以返回一个Struct Point,使C++代码保持不变,并且它也可以在不需要调用point.read()的情况下工作。 – 2012-03-14 08:15:16

+1

在这种情况下,在调用.toArray()之前,应该在Structure(指针)构造函数中调用Structure.read()。一旦JNA知道结构是数组的第一个元素,只要Structure.read()/。write()作为结构自动读/写功能的一部分被调用,它就会自动读取和写入其余元素。因此,您应该在构造函数中或在调用toArray()之前执行读取以避免多余的读取。 – technomage 2012-03-14 11:14:43

0

您的结构回归的原因是指针,所以你必须告诉JNA返回类型为结构指针,你必须声明你实现Structure.ByReference和Structure.ByValue

​​

然后

public interface Multiplyt extends Library{ 
Point.ByReference getPoints(); 
} 

的Point.ByReference在C语言一样的点*是JNA可以解析

Point.ByReference pointer = test.getPoints(); 
Point points[]; 
points = (Point[]) pointer.toArray(4); 
System.out.println("0x:"+points[0].x + " 0y:" + points[0].y + " 1x:"+ points[1].x + " 1y:" + points[1].y); 
System.out.println("2x:"+points[2].x + " 2y:" + points[2].y + " 3x:"+points[3].x + " 3y:" + points[3].y); 
+0

它完美的工作。谢谢。如果我想释放用malloc分配的内存,是否足以实现一个没有空闲(pt)的方法,其中pt是Point *,它对应于java中的“pointer”对象? – 2012-03-13 11:51:53

+0

的ByReference和根据值定义/如果你想使用非默认的语义使用时,才需要。默认情况下,结构返回值和参数按引用处理,而嵌套在其他结构中的结构按值处理。 – technomage 2012-03-13 17:20:24

+0

尽管解决方案在技术上是正确的,但您的解释并未表明*为什么*它解决了问题,并且引入了与该问题无关的无关元素。 – technomage 2012-03-13 17:25:38