Java JNA调用C函数常见问题及解决方法

news2024/11/15 11:13:34

目录

  • 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。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2070467.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

备考计算机二级Python之Day4下篇

实例解析--猜数字游戏 编写一个“猜数字游戏”的程序,在1~1000之间随机产生一个数,然后请用户循环猜这个数字,对于每个答案只回答“猜大了”或“猜小了”,直到猜对为止。输出用户的猜测次数。 使用Python语言的随机标准库random…

开源游戏开发引擎LayaAir

LayaAir是一款由Layabox公司推出的次世代全平台3D引擎,它支持2D、3D、VR与AR产品的开发,并允许开发者一次开发后同时发布为Web、小游戏、Native APP等多种平台的产品。 LayaAir引擎提供强大的IDE集成环境,包含3D场景编辑器、材质编辑器、粒子…

【linux中高级命令】

杀进程 1、lsof列出所有打开的文件,‌包括网络连接,‌从而提供关于系统状态的宝贵信息‌ #可以直接查看端口的进程 lsof -i:端口获取到进程,使用kill命令和PID来终止进程 kill -9 [PID]2、列出使用该端口的进程信息,‌包括PID …

linux上datax 安装以及使用

前言 DataX 是一款由阿里巴巴开源的数据同步工具,旨在帮助用户实现不同数据源之间的高效数据迁移和同步。无论是从传统的关系型数据库、NoSQL 数据库,还是到大数据存储系统,DataX 都能够轻松应对各种数据同步需求。通过简单的配置和灵活的插…

【解压即玩】最终幻想7 重制版中文+预购特典+全DLC,难忘的一作

数年前,一家名为神罗的公司(起初称为神罗工程所)发现了一种深埋于地底的神秘生物遗骸(被称为杰诺瓦)以及一种名为“魔晄”的能源。这家公司通过将这种生物遗骸浸泡在魔晄中来生产电力,从而迅速崛起成为全球…

一套在线工具管理服务器+DB+Redis+Mongo等

Team IDE是一个基于Web的、集成了多种开发工具和服务(MySql、Oracle、金仓、达梦、神通等数据库、SSH、FTP、Redis、Zookeeper、Kafka、Elasticsearch、Mongodb)的一体化开发环境,它不仅为开发者提供了便捷的开发体验,还支持团队协…

【文本 >>> 语音】⭐️SpringBoot 结合 jacob 简单实现一个文本朗读功能

目录 🍸前言 🍻一、环境准备 🍺二、依赖引入 💞️三、简单启动 🍹四、接口改造 4.1 封装为一个工具类 4.2 暴露一个接口 4.3 测试 🌱五、扩展 🍸前言 小伙伴们大家好,上次…

初学Python如何快速入门(内附详细攻略),一文讲清

目前python可以说是一门非常火爆的编程语言,应用范围也非常的广泛,工资也挺高,未来发展也极好。 Python究竟应该怎么学呢,我自己最初也是从零基础开始学习Python的,给大家分享Python的学习思路和方法。一味的买书看书…

AI指挥细胞大变身,脑瘤生存率跃升75%?

“ 胶质母细胞瘤(GBM),一种凶险的脑癌,曾让无数家庭陷入绝望。然而南加州大学凯克医学院的一项突破性研究,利用AI技术将脑癌细胞转化为免疫细胞,为GBM患者带来了前所未有的生存希望。 ” AI识别与重编程…

Windows系统注册表

一、修改文件图标 电脑程序怎么更换python文件的图标_mob64ca12d12b68的技术博客_51CTO博客 二、 1.打开注册的命令: 按winR快捷键,在弹出的窗口中输入:regedit 2.注册表样式 已学习至:0:47:32 课堂链…

OpenAI Sora:视频生成领域的创新力量

一、Sora 的诞生与技术原理 Sora 模型由 OpenAI 推出,其诞生背景与人工智能技术在多模态领域的不断探索和发展紧密相关。在视频数据日益丰富和重要的时代,对视频生成模型的需求愈发迫切,Sora 应运而生。 Sora 独特的技术原理使其在众多模型…

验证码短信怎么实现Java接口对接

在当今数字化时代,商家和企业对于用户身份验证的需求日益增强,这不仅是出于保护用户数据安稳的考虑,也是维护业务正常运营、防止欺诈行为的重要一环。在众多身份验证手段中,文字验证码短信因其便捷性和低成本特性,成为…

面向对象03:创建对象内存分析

本节内容视频链接:面向对象06:创建对象内存分析_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV12J41137hu?p65&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 创建对象时的内存分析涉及到理解对象如何在内存中分配和管理。‌这个过程在…

Python酷库之旅-第三方库Pandas(096)

目录 一、用法精讲 411、pandas.DataFrame.values属性 411-1、语法 411-2、参数 411-3、功能 411-4、返回值 411-5、说明 411-6、用法 411-6-1、数据准备 411-6-2、代码示例 411-6-3、结果输出 412、pandas.DataFrame.axes属性 412-1、语法 412-2、参数 412-3、…

2024年【山东省安全员B证】最新解析及山东省安全员B证找解析

题库来源:安全生产模拟考试一点通公众号小程序 2024年山东省安全员B证最新解析为正在备考山东省安全员B证操作证的学员准备的理论考试专题,每个月更新的山东省安全员B证找解析祝您顺利通过山东省安全员B证考试。 1、【多选题】《建设工程安全生产管理条…

dompdf导出pdf中文乱码显示问号?、换行问题、设置图片大小

环境:PHP 8.0 框架:ThinkPHP 8 软件包:phpoffice/phpword 、dompdf/dompdf 看了很多教程(包括GitHub的issue、stackoverflow)都没有解决、最终找到解决问题的根本! 背景:用Word模板做转PDF…

ES6笔记总结(Xmind格式):第四天

Xmind鸟瞰图: 简单文字总结: node的模块化: 1.CommonJS 规范:Node.js 遵循 CommonJS 模块规范,该规范定义了如何在服务器环境中实现模块化,包括如何定义模块、如何引入和使用模块。 2.模块的定义&…

百度文心一言API批量多线程【改写伪原创文章软件】-key免费无限写

百度文心大模型的两款主力模型ENIRE Speed、ENIRE Lite全面免费,即刻生效。 百度文心大模型的两款主力模型 这意味着,大模型已进入免费时代! 据了解,这两款大模型发布于今年 3 月,支持 8K 和 128k 上下文长度。 ER…

[MRCTF2020]Hello_ misc

解压得一个png图片和一个flag.rar 图片拖入010editor 选择带zip头的这段蓝色全部复制,file-new-new Hex File,黏贴到新文件,另存为为1.zip 要密码,线索中断(当然try to restore it.png,隐藏了zip压缩包,可…