一、我的环境:

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*的返回问题,貌似没人回答。不知道问的人是不是遇到跟我一样的问题,分享一下自己的排查过程,万一也有像我一样的初学者呢。