研究了两天,读了好些博客,终于把问题解决了
问题是:c++库里有这样的复杂结构体,以及处理
//c.h
//点
typedef struct{
int x;
int y;
}POINT;
//轮廓
typedef struct{
int num_of_points; //点数
POINT *pPoint; //POINT数组指针
}CONTOUR;
//轮廓集合
typedef struct{
int num_of_contours; //轮廓数
CONTOUR *pContour; //CONTOUR数组指针
}POLYGON;
extern "C" __declspec(dllexport)
void process_polygon(POLYGON &polygon){
polygon.num_of_contours=getNumOfContours();//伪码,意为此数为变数
polygon.pContour=new CONTOUR[polygon.num_of_contours];//动态开辟
for(int i=0;i<polygon.num_of_contours;++i){
polygon.pContour[i].num_of_points=getNumOfPoints(i);//伪码,意为此数为变数
polygon.pContour[i].pPoint=new POINT[polygon.pContour[i].num_of_points];//动态开辟
}
}
我要从java里映射这样的结构体,可以使用jna的Pointer直接映射结构体里的指针,因为传的POLYGON是引用,所以在c++库里给指针新赋的值(开的空间),在java里是可以获取到的(同一个内存空间)。Java里映射如下
//Proc.java
//点
public class POINT extends Structure{
public int x;
public int y;
//用构造函数反解出结构体,Pointer.getXXX(int offset)
public POINT(Pointer p,int offset){
x=p.getInt(offset);
offset+=8;
y=p.getInt(offset);
}
public POINT(){}
@override
protected List getFieldOrder(){return Arrays.asList("x","y");}
public class ByReference extends POINT implements Structure.ByReference{}
public class ByValue extends POINT implements Structure.ByValue{}
}
//轮廓
public class CONTOUR extends Structure{
public int num_of_points;
public Pointer pPoint=new Pointer(0);//使用指针
//用构造函数反解出结构体,Pointer.getXXX(int offset)
public CONTOUR(Pointer p,int offset){
num_of_points=p.getInt(offset);
offset+=8;
pPoint=p.getPointer(offset);
}
public CONTOUR(){}
@override
protected List getFieldOrder(){return Arrays.asList("num_of_points","pPoint");}
public class ByReference extends CONTOUR implements Structure.ByReference{}
public class ByValue extends CONTOUR implements Structure.ByValue{}
}
//轮廓集合
public class POLYGON extends Structure{
public int num_of_contours;
public Pointer pContour=new Pointer(0);
//用构造函数反解出结构体,Pointer.getXXX(int offset)
public POLYGON(Pointer p,int offset){
num_of_contours=p.getInt(offset);
offset+=8;
pContour=p.getPointer(offset);
}
public POLYGON(){}
@override
protected List getFieldOrder(){return Arrays.asList("num_of_contours","pContour");}
public class ByReference extends POLYGON implements Structure.ByReference{}
public class ByValue extends POLYGON implements Structure.ByValue{}
}
//用POLYGON.ByReference将polygon以引用的方式传到c库
void process_polygon(POLYGON.ByReference polygon);
c库处理完后,java里从指针处拿数据,如下
//c库处理完后,用CONTOUR[] contours,POINT[][] points来存数据
public void test(){
POLYGON.ByReference polygon=new POLYGON.ByReference();
process_polygon(polygon);
CONTOUR[] contours=new COUNTOUR[polygon.num_of_contours];
POINT[][] points=new POINT[polygon.num_of_contours][];
for(int i=0;i<polygon.num_of_contours;++i){
contours[i]=new CONTOUR(polygon.pContour,i*16);//每个结构体占16字节
points[i]=new POINT[contours[i].num_of_points];
for(int j=0;j<contours[i].num_of_points;++j)
points[i][j]=new POINT(coutours[i].pPoint,j*16);//每个结构体占16字节
}
}
此外,c中函数参数若为指针的话,在函数中对指针赋新值,如下
void proc_ptr(int *p){
int a=8;
p=&a;
}
将不会改变传入指针所指向的内容,原因也很简单,参数传递是传指针的值而非指针的引用,若要改变指针指向的内容,就需要改变原指针,那就要传指针的引用,如下
void proc_ptr(int *&p){
int a=8;
p=&a;
}
如此可达到目的。
我又发现了更简单的方法,不用自己去解析结构体,我当初就是这样觉得,只是没找到具体怎么实现,应该这样做,java里把指针都定义为对应结构体的ByReference,然后用这个ByReference的toArray(int size)直接转成对象数组就ok了
//Proc.java
//点
public class POINT extends Structure{
public int x;
public int y;
@override
protected List getFieldOrder(){return Arrays.asList("x","y");}
public class ByReference extends POINT implements Structure.ByReference{}
public class ByValue extends POINT implements Structure.ByValue{}
}
//轮廓
public class CONTOUR extends Structure{
public int num_of_points;
public POINT.ByReference pPoint=new POINT.ByReference();//使用指针
@override
protected List getFieldOrder(){return Arrays.asList("num_of_points","pPoint");}
public class ByReference extends CONTOUR implements Structure.ByReference{}
public class ByValue extends CONTOUR implements Structure.ByValue{}
}
//轮廓集合
public class POLYGON extends Structure{
public int num_of_contours;
public CONTOUR.ByReference pContour=new CONTOUR.ByReference();
@override
protected List getFieldOrder(){return Arrays.asList("num_of_contours","pContour");}
public class ByReference extends POLYGON implements Structure.ByReference{}
public class ByValue extends POLYGON implements Structure.ByValue{}
}
//用POLYGON.ByReference将polygon以引用的方式传到c库
void process_polygon(POLYGON.ByReference polygon);
这样就好了,polygon在c库中处理完后,这样得到数据
//c库处理完后,用CONTOUR[] contours,POINT[][] points来存数据
public void test(){
POLYGON.ByReference polygon=new POLYGON.ByReference();
process_polygon(polygon);
CONTOUR[] contours=(CONTOUR[])polygon.pContour.toArray(polygon.num_of_contours);
POINT[][] points=new POINT[polygon.num_of_contours][];
for(int i=0;i<polygon.num_of_contours;++i){
points[i]=(POINT[])contours[i].pPoints.toArray(contours[i].num_of_points);
}
}