一、我的环境:
1)c++:
windows生成dll:
Qt5.9.2+“x86_64-w64-mingw32/8.1.0/”。这里需要说明的是windows下需要C++换一下64位编译器,原来的qt官网自带的版本是32位的,要不就要换java的jdk成32位的,感觉折腾更麻烦,不如换c的编译器方便。
linux生成so:
直接用的g++,“x86_64-kylin-linux/5.3.1”
目标:x86_64-kylin-linux
2)Java:
jdk:1.8.0_191
Jna:3.0.9
<dependency> <groupId>com.sun.jna</groupId> <artifactId>jna</artifactId> <version>3.0.9</version> </dependency>
二、想调的C函数:
头文件:
extern "C" const char* HmyAdd(int a, int b);
出问题的cpp:
#include "testadd.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
const char* HmyAdd(int a, int b)
{
char outstr[256];
memset(outstr,0,256);
if(outstr!=0)
{
sprintf(outstr,"汉字out DLL汉字: %d + %d==%d\n",a,b,(a+b));
//printf("%s",outstr);
}
//这样写是不对的,因为返回的其实是函数内部的局部变量,感觉jna用String吃不到返回值
//但是貌似如果是C++调用,是可以的
return outstr;
}
三、Java的接口:
import com.sun.jna.Library;
/**
* @author hound81
*/
public interface LoadTcSo extends Library {
//定义动态库接口方法
public abstract String HmyAdd(int a,int b);
}
System.setProperty("jna.encoding", "utf8");
//需要和对应的dll的编码对应起来。我感觉可能我这里qt的本身设置的编码也是utf8,如果是vs可能就要改成gb18030。如果汉语是乱码,可以试试换一下设置jna的编码
//这里getTcdllpath()换成自己的 "动态库路径+xxx.so"。
log.info("尝试载入Dll:"+ getTcdllpath());
LoadTcSo INSTANCE = null;
try {
INSTANCE = (LoadTcSo) Native.loadLibrary(getTcdllpath(), LoadTcSo.class);
} catch (Exception e) {
e.printStackTrace();
}
if(INSTANCE!=null){
String retstr= INSTANCE.HmyAdd(333,333);
log.info("载入Dll,并且调用函数,返回char*结果:" + retstr);
}else {
log.warn("载入Dll失败:"+getTcdllpath());
}
四、改好的cpp
不太清楚是不是这个原理,只是感觉全局变量存放在数据区(jna用String是能读的到),局部变量存放在栈区, 动态变量存放在堆区(jna也能得到),函数代码放在代码区。所以返回的char*指向的应该是个全局变量,或者是自己new或者malloc出来的就没问题了。我用的这个小功能感觉还是放在全局变量算了,没多少,省的new完了,还想着delete的事情。【还没试,如果dll里嗷嗷的new,也不delete,jna会不会帮着回收,还是一直涨然后就溢出了?】
目前看者两个方法都行:
1)返回全局的:
char retp[1024];
const char* HmyAdd(int a, int b)
{
memset(retp,0,1024);
char outstr[256];
memset(outstr,0,256);
if(outstr!=0)
{
sprintf(outstr,"汉字out DLL汉字: %d + %d==%d\n",a,b,(a+b));
}
strcpy(retp,outstr);
return retp;
}
2)返回malloc出来的:
const char* HmyAdd(int a, int b)
{
char* retp = (char*)malloc(1024);
memset(retp,0,1024);
char outstr[256];
memset(outstr,0,256);
if(outstr!=0)
{
sprintf(outstr,"汉字out DLL汉字: %d + %d==%d\n",a,b,(a+b));
//printf("%s",outstr);
}
strcpy(retp,outstr);
return retp;
}
总结:最近学习这个jna调用的时候,看了不少文章,有人说了复杂的结构体互传,或者jna的传引用或者指针point,这些问题都有人说,试了试也能用。还有人问什么Java的String收不下来C++的char*的返回问题,貌似没人回答。不知道问的人是不是遇到跟我一样的问题,分享一下自己的排查过程,万一也有像我一样的初学者呢。