JNI調用c++函數,該函數的參數是結構體(——對象的傳遞)

第三方C++函數接口爲 int api_get_logfile(Struct fileinfo tfile),參數是個結構體,且套了另一個結構體:

struct fileinfo{
 char *fullpath;
 int filesize;
 int filemode;
 struct disnode *tnode;
};

struct disnode{
 int number;
 struct {
  int node;
  int stat;
 }s[number];

};

java中沒有結構體的概念,對於結構體你可以建立一個class與其對應,但是轉化過程必須自己寫。
例如你的結構體爲fileinfo,那麼你就可以建立一個FileInfo類對應他,但是在C中必須自己轉化,也就是傳入一個FileInfo的對象,然後對FileInfo對象的屬性通過fileinfo結構體逐一複製
又或者你不建立class與其對應,多建立幾個String類型來接受結構體中的各個信息也可以。
但是java是不支持char *這種形式的字符串的,所以你必須把C中字符串表示方式轉換成java的String,java中String類型在c中表示形式其實就是jstring類型,它本身是一個複雜類型(jobject類型),實際爲執行內存的指針。
對於如何把char*轉變成jstring,你可以查看jni相關文檔,jni有很多內置函數實現這些功能。
對於複雜類型的轉換,如結構體轉換成jobject,需要自己手動轉換。java不直接支持結構體特性,因爲java的jni不是僅僅去支持C的。

////////////////

//通過GetObjectClass方法得到這個對象
 jclass objectClass = (env)->GetObjectClass(obj);
//通過GetFieldID方法得到這個對象的fsize屬性
jfieldID fs = (env)->GetFieldID(objectClass,"filesize","I");
//再通過SetIntField()方法把這個屬性和結構體一一對應賦值對嗎?類似於下面這樣:
(env)->SetIntField(obj,fs,40);


不過有個地方不知道具體怎麼做:
如果這個FileInfo對象的有個屬性是一個數組的話,通過GetFieldID()這個JNI函數怎麼取得這個數組?
又怎麼把這個數組和結構體內的數組對應起來呢?

////////

JNI裏面也有專門處理數組的函數,其實如果你足夠了解java的話也應該知道數組也是一個object,其簽名爲[xtype的形式,其中x爲[的數量,type爲數組類型,例如[[i相當於int[][],[[Ljava/util/Date相當於Date[][]。所以數組本身也可以用GetObjectClass來獲得,但是處理數組元素需要專門的jni內置函數來處理。
最後提醒你一句,一定要記得回收內存噢。jni的字符串與數組最容易出現內存泄漏。

例如:FileInfo類有個屬性是 int ss[5]:

public class FileInfo{
   public int filesize;
   public int ss[] = new int[5];
}

在JNI的封裝中:

jclass objectClass = (env)->GetObjectClass(obj); //obj就是FileInfo類的實際對象
jfieldID fs = (env)->GetFieldID(objectClass,"filesize","I"); //可以獲取到int型的filesize這個屬性了

jfieldID ss = (env)->GetFieldID(objectClass,"ss","[I"); //這樣是不是可以獲取到int型的數組ss了?

如果可以的話,怎麼對這個ID ss進行實際的訪問操作?

jint jfs=(*env)->GetObjectField(env,cl,fs); //通過ID取得具體的數組

///////////

jfieldID fs = (env)->GetFieldID(objectClass,"filesize","I");
這樣只是獲得對象字段的句柄指針,並沒有獲得字段的,要獲得字段的還需要其它操作,例如:
jint jfs=(*env)->GetObjectField(env,cl,fs);
如果獲得的是jstring類型或者是數組類型還需要進行轉換,轉換成char[]類型或者char*類型,例如
char* str=(*env)->GetStringUTFChars(env,jstr,NULL);
如果是基本數據類型數組的話,訪問其內部元素用GetXxxArrayElements(env,jarray,0);函數Xxx是類型名稱,返回Xxx*類型,
如int * i=GetIntArrayElements(env,jint,0)
如果是對象型數組就是jobject jobj=GetObjectArrayElement(env,jobjectArray,jsize),jobject是數組變量,jsize是偏移量,返回值是數組中對應偏移量的值。

舉例,java用一個類作爲參數傳遞給C++的函數,C++內部聲明瞭一個結構體來對應這個類的屬性
類中有個屬性是個int型的數組:int info[30]
在JNI封裝函數中這樣寫:

//取得類對象
jclass objectClass = (env)->GetObjectClass(sobj);  //sobj即傳遞進來的類的對象
//取得該數組屬性的ID
jfieldID jarr_info = (env)->GetFieldID(objectClass,"info","[I"); //參數“[I”表示這個是int型數組
//通過ID取得具體的數組
jintArray jintarr = (jintArray)(env)->GetObjectField(sobj,jarr_info); //參數sobj是該封裝函數自動參數(JNIEnv *env, jclass sobj)中的jclass

//以上部分執行沒有問題,問題出在下面語句:

//要對數組進行操作,要取得該數組的數組指針,通過JNI的函數GetIntArrayElements()來取得:
jint *pia = (env)->GetIntArrayElements(jintarr,0); 

class中有個屬性爲String類型:

public class FileInfo{
   public String name; 
}
JNI中:

//取得類對象
jclass objectClass = (env)->GetObjectClass(sobj);  //sobj即傳遞進來的類的對象:new FileInfo()
//取得該String屬性的ID
jfieldID jname = (env)->GetFieldID(objectClass,"name","Ljava/lang/String;"); //參數“Ljava/lang/String;”表示這個是String型
//取得該屬性的具體值:
jstring js = (jstring)(env)->GetObjectField(sobj,jname);



發佈了10 篇原創文章 · 獲贊 3 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章