2012-03-13 36 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