目录
- 1 undefined symbol:xxx
- 2 Java映射C数组乱码
- 3 Java使用String接收不到C函数返回的char*
- 4 Unable to load DLL 'xxx.dll'
- 5 java.lang.UnsatisfiedLinkError: %1 不是有效的 Win32 应用程序
- 6 无效的ELF头
- 7 Structure array elements must use contiguous memory
- 8 java.lang.IndexOutOfBoundsException
以下是博主自己使用JNA过程中遇到的一些问题汇总,分享给大家,少踩坑。
1 undefined symbol:xxx
在so中找不到指定的符号,往往是因为函数在so中没有定义导致的。
解决方法:
检查C中函数是否正确定义。
2 Java映射C数组乱码
直接使用getBytes传参乱码
typedef struct
{int enable;char static_ip[20];char netmask[20];char gateway[20];char dns1[20];char dns2[20];
} network_eth;extern "C"{int sdk_set_network_eth(const char* ip, network_eth* network_param);
}
//函数定义
int sdk_set_network_eth(const char *ip, network_eth *network_param){if (strlen(ip) == 0 || network_param == NULL){printf("sdk_set_network_eth param error!\n");return -1;}printf("ip:%s\n",ip);printf("network_eth enable:%d\n",network_param->enable);printf("network_eth static_ip:%s\n",network_param->static_ip);printf("network_eth netmask:%s\n",network_param->netmask);printf("network_eth gateway:%s\n",network_param->gateway);printf("network_eth dns1:%s\n",network_param->dns1);printf("network_eth dns2:%s\n",network_param->dns2);return 0;
}
Java模拟结构体:
public class NetWorkEth extends Structure {
// 成员变量声明,与C结构体中声明的变量顺序一一对应
public int enable;
public byte[] static_ip = new byte[20];
public byte[] netmask = new byte[20];
public byte[] gateway = new byte[20];
public byte[] dns1 = new byte[20];
public byte[] dns2 = new byte[20];// 接口类声明
public static class ByReference extends NetWorkEth implements Structure.ByReference{}
public static class ByValue extends NetWorkEth implements Structure.ByValue{}/**
* 定义取值次序,需要与c中对齐,不然会报NoSuchFieldError
* @return
*/
@Override
protected List getFieldOrder(){return Arrays.asList(new String[] {"enable", "static_ip", "netmask", "gateway", "dns1", "dns2"});}
}// 测试C函数
@Test
public void NetworkTest(){NetWorkEth.ByReference nwbr = new NetWorkEth.ByReference();String ip = "0.0.0.0";int res = CLibrary.INSTANCE.sdk_set_network_eth(ip,null);log.error("res="+res);Assert.assertEquals(-1,res);nwbr.enable = 1;// 错误用法
// nwbr.static_ip = "10.20.6.10".getBytes() ;
// nwbr.netmask = "255.255.255.0".getBytes();
// nwbr.gateway = "192.168.122.134".getBytes();
// nwbr.dns1 = "114.114.114.114".getBytes();
// nwbr.dns2 = "8.8.8.8".getBytes();// 正确用法nwbr.static_ip = Arrays.copyOf("10.20.6.10".getBytes(),20);nwbr.netmask = Arrays.copyOf("255.255.255.0".getBytes(),20);nwbr.gateway = Arrays.copyOf("192.168.122.134".getBytes(),20);nwbr.dns1 = Arrays.copyOf("114.114.114.114".getBytes(),20);nwbr.dns2 = Arrays.copyOf("8.8.8.8".getBytes(),20);res = CLibrary.INSTANCE.sdk_set_network_eth(ip,nwbr);Assert.assertEquals(0,res);}
乱码原因:
一开始以为C++和Java的数组类型都是一样的,直接用C++的char[]对应Java的byte[],但是发现错误,不可行,查找资料发现C++的数组类型在内存中是连续存储的,而Java的数组不一定是连续的。
对C中的char数组类型赋值时,不能直接给数组赋值,要使用Arrays.copyOf(String.getBytes(),20)赋值,数组长度和C结构体中声明的长度保持一致。
在某些情况下,虽然使用String.getBytes()转换也能成功,但大多数情况下,使用该方法会出现乱码,不建议使用String.getBytes()。推荐使用Arrays.copyOf()。
解决方法:
使用使用Arrays.copyOf()
3 Java使用String接收不到C函数返回的char*
JNA使用String无法直接接收C 函数返回类型为char*的值,必须要用Pointer进行接收。
【注意】当C函数的参数为char*、const char*用做输入时,JNA可以使用String类型进行传参
,此时可以正常调用C函数;
但当C函数的参数类型为char*且用作输出时,使用String类型无法正常接收,必须使用Pointer进行处理。
假设有下面的函数:int sdk_temp_buf_get(char* databuf,const char* ip);
函数接收一个不为空且ip为指定内容的主机地址,返回一个温度值保存在databuf中
【实例】使用String接收char*返回结果
解决方法: 使用Pointer接收char*类型的返回值
4 Unable to load DLL ‘xxx.dll’
产生原因:
动态库和jdk位数不匹配
64位的jdk只能调用64位的dll,32位也一样。如果使用的jdk和dll位数不同,会报Unable to load DLL ‘xxx.dll’
解决方法:
确保动态库和jdk的位数相同,32位的so就用32位的jdk,64位so就用64位jdk。
5 java.lang.UnsatisfiedLinkError: %1 不是有效的 Win32 应用程序
产生原因:
动态库类型和系统类型不匹配,多是由于在windows下调用了Linux下的so。如果排除了这个原因,则是动态库和jdk位数不匹配,
64位的jdk只能调用64位的dll,32位也一样。
解决方法:
确保动态库类型和系统类型匹配,windows下调用dll,Linux下调用so;确保动态库和jdk的位数相同。
6 无效的ELF头
windows系统下的动态库后缀名为.dll,Linux下的动态库后缀名为.so。
不能在windows系统上调用.so库中的函数,同样也不能在Linux系统上调用.dll文件。
Linux下调用.dll报错:无效的ELF头
解决方法:
确保动态库类型和系统类型匹配
7 Structure array elements must use contiguous memory
这个报错意思是结构数组元素必须使用连续内存,一般发生在用结构体数组做参数时,传参直接new了对象赋值给数组。
看下面一个例子:
Java接口声明:int changeObjs(Structure per[], int size);
Person[] per = new Person[2];
Person p1 = new Person();
Person p2 = new Person();
p1.age = 1;
p1.name = Arrays.copyOf(“k1”.getBytes(),20);
p2.age = 2;
p2.name = Arrays.copyOf(“k2”.getBytes(),20);
per[0] = p1;
per[1] = p2;
结构体数组必须使用连续的内存区域。p1,p2都是new出来的对象,不可能连续
,用传统方式初始化数组不能解决。
解决方法:使用JNA的toArray产生内存连续的结构体数组
Person pb = new Person();
Person[] pers = (Person[]) pb.toArray(2);
pers[0].age = 1;
pers[0].name = Arrays.copyOf("k1".getBytes(),20);
pers[1].age = 2;
pers[1].name = Arrays.copyOf("k2".getBytes(),20);
CLibrary.INSTANCE.changeObjs(pers, 2);
8 java.lang.IndexOutOfBoundsException
原因:在结构体数组做参数时,Java接口声明中错误把参数类型写成Person.ByValue
解决方法:将参数类型改为结构体本身即可
即不带ByReference或ByValue。结构体数组做参数时,要区别于非数组的ByReference和ByValue。