上一篇介绍了JNA框架开发的入门,项目是基于JNA框架开发,本文的焦点是参数的地址传递。
在java中都是值传递,但是因为使用JNA框架,目标函数是C/C++是有地址变量的,很多时候都需要将变量的结果带回,因此,地址传递在JNA项目中几乎是必须的。
C/C++
int add(int a, int b, int *c, char **msg) { *c = (a + b) * 2; char *string = "hello world!"; *msg = string; return a + b; }
如果java这样写
public class HelloJNA { public interface LibraryAdd extends Library { // 这里使用绝对路径加载 LibraryAdd LIBRARY_ADD = Native.load("/program/cpp/libhello.so", LibraryAdd.class); int add(int a, int b, int c, String msg); } public static void main(String[] args) { int c = 0; String msg = "start"; // 调用so映射的接口函数 int add = LibraryAdd.LIBRARY_ADD.add(10, 15, c, msg); System.out.println("相加结果:" + add); } }
那么不管add函数对c和msg做了何种改变,返回java中,值都不会被变更。
三、指针参数Pointer那么如何实现类似C语言那样的地址传递,或者说指针传递呢?在JNA框架中,我们可以借助一个类完成,他就是Pointer。
com.sun.jna.Pointer,指针数据类型,用于匹配转换映射函数的指针变量。
Pointer c = new Memory(50); Pointer msg = new Memory(50);
说明:
这样的指针变量定义很像C的写法,就是在定义的时候申请空间。比如这里就申请50个空间
根据测试结果对于字符串,一个空间对于两个字符左右。如果返回的结果长度比分配的空间大,则会报错
Exception in thread “main” java.lang.IndexOutOfBoundsException: Bounds exceeds available space : size=6, offset=8
最后可以这样释放申请的空间
Native.free(Pointer.nativevalue(c)); //手动释放内存 Pointer.nativevalue(c, 0); //避免Memory对象被GC时重复执行Nativ.free()方法 Native.free(Pointer.nativevalue(msg)); Pointer.nativevalue(msg, 0);2、使用
import com.sun.jna.Library; import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.Pointer; public class HelloJNA_Pointer { public interface LibraryAdd extends Library { LibraryAdd LIBRARY_ADD = Native.load("/program/cpp/libhello.so", LibraryAdd.class); int add_c(int a, int b, Pointer c, Pointer msg); } public static void main(String[] args) { Pointer c = new Memory(50); Pointer msg = new Memory(8); // 调用so映射的接口函数 int add = LibraryAdd.LIBRARY_ADD.add_c(10, 15, c, msg); System.out.println("相加结果:" + add); // 指针变量 System.out.println("c的值:" + c.getInt(0)); // 这样才能拿到 System.out.println("msg的值:" + msg.getPointer(0).getString(0)); Native.free(Pointer.nativevalue(c)); //手动释放内存 Pointer.nativevalue(c, 0); //避免Memory对象被GC时重复执行Nativ.free()方法 Native.free(Pointer.nativevalue(msg)); //手动释放内存 Pointer.nativevalue(msg, 0); //避免Memory对象被GC时重复执行Nativ.free()方法 } }
说明:
①、传递参数直接传Pointer 定义出来的对象即可
②、取值时,需要根据变量的类型采用不同的API读取,例如,如果函数是int*变量,那么就c.getInt(0)
如果是char **msg,就msg.getPointer(0).getString(0)
③、指针说明:一层指针就直接取值c.getInt(0),其中0表示偏移量从0开始;如果是二级指针,msg.getPointer(0).getString(0),表示指针的指针再取值;多级指针以此类推。
[root@192 cpp]# java -jar JNATestC.jar 相加结果:25 c的值:50 msg的值:hello world!四、最后
项目搭建请回看:JNI便捷开发框架JNA框架之入门(一)
有个知识点参考:C语言中字符串变量的函数值传递与指针传递
上一篇 JNI便捷开发框架JNA框架之入门(一)
下一篇JNI便捷开发框架JNA框架之参数引用传递ByReference(三)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)