JNI调用c++函数,该函数的参数是结构体(——对象的传递)

来源:互联网 发布:mac开发网站 编辑:程序博客网 时间:2024/06/05 10:47

第三方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即传递进来的类的对象//取得该数组属性的IDjfieldID 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属性的IDjfieldID jname = (env)->GetFieldID(objectClass,"name","Ljava/lang/String;"); //参数“Ljava/lang/String;”表示这个是String型//取得该属性的具体值:jstring js = (jstring)(env)->GetObjectField(sobj,jname);  
阅读全文
0 0
原创粉丝点击