JNI内两种方式从C/C++中传递一维、二维、三维数组数据至Java层详细梳理
目录
0 前言
1 准备工作介绍
2 一维数组
2.1 return形式
2.2 参数形式
3 二维数组
3.1 return形式
3.2 参数形式
4 三维数组
4.1 return形式
4.2 参数形式
5 测试代码
6 结果说明
0 前言
就如之前我写过的一篇文章【JNI内形参从C代码中获取返回值并返回到Java层使用】中所描述的一样,JNI编程往往需要考虑的就是如何将C/C++中计算分析得到的数据传递至Java层。传递的方式就有两种:①直接通过函数return出来;②再就是通过形参获取得到。在以上文章内介绍了int值得传递情况,这篇文章则具体讲述数组得传递方式和操作,包括一维数组、二维数组以及三维数组,数组使用到三维基本满足了绝大部分的使用需求了。
之所以写这篇文章,也是因为检索了很久对于数组在JNI内传递数据方式只看到第一种通过return方式传递的。为此就将自己工作整理出来,实现数组通过形参的方式传递数据给java层。
1 准备工作介绍
在写测试案例之前需要有系列的准备工作,由于这不是重点,该部分我简单介绍一下。首先需要创建java工程,然后编写java文件,生成JNI头文件,最后编译成动态库。这里面具体可以参考:【IntelliJ IDEA平台下JNI编程(一)—HelloWorld篇_idea jni_走召大爷的博客-CSDN博客】
本次编写环境Ubuntu18.04 、gcc7.5.0、生成.so动态库、IDEA平台。以下分别介绍在jni层不同维度数组不同形式传递数据的代码写法,具体介绍可以看代码内部注释。
2 一维数组
2.1 return形式
//一维数组 return形式向JAVA传递数据
JNIEXPORT jdoubleArray Java_com_test_java_JNItest_test0(JNIEnv *env, jobject)
{int n = 3; //构造/模拟一个数组double test[3] = {0.0,1.0,2.0};//定义一维数组,数组元素个数为n=3jdoubleArray one = env->NewDoubleArray(n);env->SetDoubleArrayRegion(one,0,n,test); return one;}
2.2 参数形式
//一维数组 形参向JAVA传递数据
JNIEXPORT jint Java_com_test_java_JNItest_test3
(JNIEnv *env, jobject,jdoubleArray result)
{int n = 3;//构造/模拟一个数组double test[3] = {0.0,1.0,2.0};env->SetDoubleArrayRegion(result,0,n,test); return 0;
}
3 二维数组
3.1 return形式
//二维数组 return形式向JAVA传递数据
JNIEXPORT jobjectArray Java_com_test_java_JNItest_test1(JNIEnv *env, jobject)
{//构造二维数组double test[2][3] = {{1.0,2.0,3.0},{3.0,3.0,6.0}};//一维数组 类型定义jclass ArrCls1 = env->FindClass("[D"); //创建一个有polygonpointNum个元素,每个元素的值是NULL的一维数组的数组 jobjectArray second = env->NewObjectArray(2, ArrCls1, NULL); //等同二维数组//对于二维数组其内容是每一个一维数组,那么就循环定义一维数组,直接存入结果里面 //对于测试的二维数组:其为2x3固定的,不然通过下面循环可以获取变长的数组内容for(int i = 0;i < 2;i++){ int num = 3;//定义一维数组,数组元素个数为num=3jdoubleArray darr = env->NewDoubleArray(num);//将test的内容赋值给darrenv->SetDoubleArrayRegion(darr, 0, num, test[i]);//然后再将darr一维数组内容直接按顺序赋值给second二维数组env->SetObjectArrayElement(second, i, darr); //删除临时元素darr数组 env->DeleteLocalRef(darr); } return second;}
3.2 参数形式
//二维数组 形参向JAVA传递数据
JNIEXPORT jint Java_com_test_java_JNItest_test4(JNIEnv *env, jobject, jobjectArray result)
{//构造二维数组double test[2][3] = {{1.0,2.0,3.0},{3.0,3.0,6.0}};//对于二维数组其内容是每一个一维数组,那么就循环定义一维数组,直接存入结果里面 //对于测试的二维数组:其为2x3固定的,不然通过下面循环可以获取变长的数组内容for(int i = 0;i < 2;i++){ int num = 3;//定义一维数组,数组元素个数为num=3jdoubleArray darr = env->NewDoubleArray(num);//将test的内容赋值给darrenv->SetDoubleArrayRegion(darr, 0, num, test[i]);//然后再将darr一维数组内容直接按顺序赋值给二维结果数组,如此就将c/c++内部的数组内容通过result传递到java层了env->SetObjectArrayElement(result, i, darr); //删除临时元素darr数组 env->DeleteLocalRef(darr); } return 0;}
4 三维数组
4.1 return形式
//三维数组 return形式向JAVA传递数据
JNIEXPORT jobjectArray Java_com_test_java_JNItest_test2(JNIEnv *env, jobject)
{//构造一个三维数组,示例为两个多边形,每个多边形3个顶点,每个顶点由x,y组成double test[2][3][2] = {{{1.0,2.0},{3.0,5.0},{2.0,4.0}},{{1.0,2.0},{3.0,5.0},{2.0,4.0}}};int polygonNum = 2;//二维数组类型定义jclass ArrCls2 = env->FindClass("[[D"); //实例化三维数组对象,第一个参数数据的大小,第二个参数用来实例化用的类是一个二维数组,也就是数组里的每个元素都是一个二维数组 jobjectArray three = env->NewObjectArray(polygonNum, ArrCls2, NULL); //这样three就是一个三维数组。for(int i = 0;i < polygonNum;i++) { int polygonpointNum = 3;//一维数组 类型定义jclass ArrCls1 = env->FindClass("[D"); //创建一个有polygonpointNum个元素,每个元素的值是NULL的一维数组的数组 jobjectArray second = env->NewObjectArray(polygonpointNum, ArrCls1, NULL); //等同二维数组for (int j = 0; j < polygonpointNum; j++) { jdouble tmp[2]; //构造每一个一维存储单元/* make sure it is large enough! */tmp[0] = test[i][j][0]; tmp[1] = test[i][j][1]; //也可以不构造和赋值,后面one的赋值可以env->SetDoubleArrayRegion(one, 0, 2, test[i][j]);也可以的 //定义有两个元素的一维数组jdoubleArray one = env->NewDoubleArray(2); //把tmp里数据从0开始传递2个到one里 env->SetDoubleArrayRegion(one, 0, 2, tmp); //给二维数组second的第j个元素设置值 env->SetObjectArrayElement(second, j, one); //注意理解内容填充(数组初始化)//删除临时元素one数组 env->DeleteLocalRef(one); } //给三维数组里的第i个元素设置值,值是一个有一个元素组成的二维数据env->SetObjectArrayElement(three, i, second); //删除临时元素二维数组 env->DeleteLocalRef(second); } return three;
}
4.2 参数形式
//三维数组 形参向JAVA传递数据
JNIEXPORT jint Java_com_test_java_JNItest_test5(JNIEnv *env, jobject, jobjectArray result)
{//构造一个三维数组,示例为两个多边形,每个多边形3个顶点,每个顶点由x,y组成double test[2][3][2] = {{{1.0,2.0},{3.0,5.0},{2.0,4.0}},{{1.0,2.0},{3.0,5.0},{2.0,4.0}}};int polygonNum = 2;for(int i = 0;i < polygonNum;i++) { int polygonpointNum = 3;//一维数组 类型jclass arrClass = env->FindClass("[D"); //创建一个有polygonpointNum个元素,每个元素的值是NULL的一维数组的数组 jobjectArray second = env->NewObjectArray(polygonpointNum, arrClass, NULL); //等同二维数组//给一维数据填充值 for (int j = 0; j < polygonpointNum; j++) { jdouble tmp[2]; //构造每一个一维存储单元tmp[0] = test[i][j][0]; tmp[1] = test[i][j][1]; //也可以不构造和赋值,后面one的赋值可以env->SetDoubleArrayRegion(one, 0, 2, test[i][j]);也可以的//创建一个有2个元素的一维数组jdoubleArray one = env->NewDoubleArray(2); //把tmp里数据从0开始传递2个到one里 env->SetDoubleArrayRegion(one, 0, 2, tmp); //给二维数组second的第j个元素设置值 env->SetObjectArrayElement(second, j, one); //注意理解内容填充(数组初始化)//删除临时元素one数组 env->DeleteLocalRef(one); } //给需要传出的三维数组里的每个元素设置值,值是一个有一个元素组成的二维数据env->SetObjectArrayElement(result, i, second); //删除临时元素二维数组 env->DeleteLocalRef(second); } return 0;}
5 测试代码
在java内的测试代码如下:
package com.test.java;/*** @author yh* @version 1.0* @date 23-3-6 下午8:58*/
public class JNItest {static {System.load("/root/workspace-yh/javaProjectTest/jni/libjnitest.so");}public native double[] test0();public native double[][] test1();public native double[][][] test2();public native int test3(double[] result);public native int test4(double[][] result);public native int test5(double[][][] result);public void printOneArray(double[] t){int n = t.length;for(int i = 0;i < n;i++){System.out.println(t[i]);}}public void printSecondArray(double[][] t){int n = t.length;for(int i = 0;i < n;i++){int m = t[i].length;String temp = "";for(int j = 0;j < m;j++){temp += t[i][j]+",";}System.out.println(temp);}}public void printThreeArray(double[][][] t){int n = t.length;for(int i = 0;i < n;i++){int m = t[i].length;for(int j = 0;j < m;j++){String temp = "";int k = t[i][j].length;for(int l = 0;l < k;l++){temp += t[i][j][l]+",";}System.out.println(temp);}}}public static void main(String[] args){JNItest JNI = new JNItest();double[] a3 = new double[3];double[][] a4 = new double[2][2];double[][][] a5 = new double[2][3][2];System.out.println("-------------------test0-----------------");double[] a0 = JNI.test0();JNI.printOneArray(a0);System.out.println("-------------------test3-----------------");int rnt3 = JNI.test3(a3);JNI.printOneArray(a3);System.out.println("-------------------test1-----------------");double[][]a1 = JNI.test1();JNI.printSecondArray(a1);System.out.println("-------------------test4-----------------");int rnt4 = JNI.test4(a4);JNI.printSecondArray(a4);System.out.println("-------------------test2-----------------");double[][][]a2 = JNI.test2();JNI.printThreeArray(a2);System.out.println("-------------------test5-----------------");int rnt5 = JNI.test5(a5);JNI.printThreeArray(a5);} }
6 结果说明
直接执行main函数,控制台打印信息:
根据结果可以看到,两种方式均把c/c++层数据传递到了java层了。那么后面根据工程需要想怎么传递数据就怎么传递数据,想怎么使用接口就怎么设计接口了。
参考文章:
JNI 返回二维、三维,char、float、int、long型数组到java层_谢文浩博客-CSDN博客_jni 返回二维数组
Android Studio开发之JNI层开发 --- jni层返回二维数组对象_Jimmy-CSDN博客_jni 返回二维数组
android jni jobjectArray存储输出不同类型的数据_阿文的博客-CSDN博客_jni jobjectarray
相关文章:
JNI内两种方式从C/C++中传递一维、二维、三维数组数据至Java层详细梳理
目录 0 前言 1 准备工作介绍 2 一维数组 2.1 return形式 2.2 参数形式 3 二维数组 3.1 return形式 3.2 参数形式 4 三维数组 4.1 return形式 4.2 参数形式 5 测试代码 6 结果说明 0 前言 就如之前我写过的一篇文章【JNI内形参从C代码中获取返回值并返回到Java层使…...
快递计费系统--课后程序(Python程序开发案例教程-黑马程序员编著-第3章-课后作业)
实例5:快递计费系统 快递行业高速发展,我们邮寄物品变得方便快捷。某快递点提供华东地区、华南地区、华北地区的寄件服务,其中华东地区编号为01、华南地区编号为02、华北地区编号为03,该快递点寄件价目表具体如表1所示。 表1 寄…...
JS - 自定义一周的开始和结束,计算日期所在月的周数、所在月第几周、所在周的日期范围
自定义一周的开始和结束,计算日期所在月的周数、所在月第几周、所在周的日期范围一. 方法使用二. 实现案例一. 方法使用 根据月开始日期星期几、月结束日期星期几,计算始周、末周占月的天数(每周周期段:上周六 —— 本周五&#x…...
Linux :理解编译的四个阶段
目录一、了解编译二、认识编译的四个阶段(一)预处理(二)编译(三)汇编(四)链接1.静态链接2.动态链接三、分步编译(一)创建.c文件(二)预…...
197.Spark(四):Spark 案例实操,MVC方式代码编程
一、Spark 案例实操 1.数据准备 电商网站的用户行为数据,主要包含用户的 4 种行为:搜索,点击,下单,支付 样例类: 2. Top10 热门品类 先按照点击数排名,靠前的就排名高;如果点击数相同,再比较下单数;下单数再相同,就比较支付数。 我们有多种写法,越往后性能越…...
Vue 项目如何迁移小程序
最近我们看到有开发者在社群里提出新的疑惑「我手头已经有一个成熟的 HTML5 项目了,这种项目可以转为小程序在 FinClip 环境中运行吗?」。 经过工作人员的沟通了解,开发者其实是想将已有的 Vue 项目转为小程序,在集成了 FinClip …...
unit1-问候以及介绍
unit1-问候以及介绍 重点表达 1、问好 使用hello 和 hi 来打招呼。hello可以使用在正式和非正式的场合。hi是非正式的。但是hello 和 hi 都可以在一天的任何时段使用。 Hello. 你好。 Hi! 嗨! 介绍你的姓名 使用 I’m 和 My name is 告诉别人你的名字。 I’m Pau…...
杂记——19.git上传时出现the remote end hung up unexpectedly错误
git是大家常用的项目版本控制工具,熟练地使用git可以提高开发效率,但是有时在使用git推送代码时,会提示“the remote end hung up unexpectedly”的问题,那么git推送代码提示“the remote end hung up unexpectedly”怎么解决呢&a…...
python123平台题目
作业二 1. 2的n次方描述输入格式输出格式输入输出实例代码解析2. 输出最大值描述输入格式输出格式输入输出示例代码解析3. 字符串输出描述输入格式输出格式输入输出示例代码解析4. 字符串长度描述输入格式输出格式输入输出示例代码解析...
ROS学习笔记(六):TF坐标变换
ROS学习笔记(六):TF坐标变换TF的基本知识TF工具tf_monitortf_echostatic_transform_publisherview_frames创建TF广播器创建TF监听器TF的基本知识 TF是一个让用户随时间跟踪多个坐标系的功能包,它使用树形数据结构,根据…...
【python】为你绘制玫瑰一束,爱意永存
前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 若是有真情,爱意如溪水, 若是有真爱,爱意如阳光, 若是两情相悦,又岂在朝朝暮暮, 女子淡淡的情愫,深深地想念, 浓浓的爱意&a…...
智能家居创意产品一Homkit智能通断器
智能通断器,也叫开关模块,可以非常方便地接入家中原有开关、插座、灯具、电器的线路中,通过手机App或者语音即可控制电路通断,轻松实现原有家居设备的智能化改造。 随着智能家居概念的普及,越来越多的人想将自己的家改…...
【数据库】MySQL表的增删改查(基础命令详解)
写在前面 : 语法中大写字母是关键字,用[]括这的是可以省略的内容。文中截图是相对应命令执行完得到的结果截图。1.CRUD 注释:在SQL中可以使用“--空格描述”来表示注释说明.CRUD:即增加(Create)、查询(Retrieve)、更新(Update)、删除(Delete)四个单词的首…...
2023年全国最新保安员精选真题及答案15
百分百题库提供保安员考试试题、保安职业资格考试预测题、保安员考试真题、保安职业资格证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 151.该图所要表达的是()消防器材。 A:地上消防栓 B:灭火器 …...
KPN对任意形状文本检测
文章目录一、研究背景二、方法流程1. 特征提取2. 核建议3. 实例无关特征图4. 轮廓生成5. 其余部分内容三、不足一、研究背景 相比起基于 FCN 网络的文本边缘检测网络,KPN网络可以更好地处理文本之间的间隔。 二、方法流程 1. 特征提取 FCN 和 FPN FCN(全卷积神经…...
同城外卖跑腿系统源码分析
外卖订餐已经成为很多“社畜”日常不可分割的一部分,足不出户,只需要一部电子设备即可在线订餐,并且可提供的选择非常多样化,与传统的电话订餐外卖模式相比也更便捷的多。 因此,同城外卖跑腿系统源码得以爆火ÿ…...
SCL_PFENET跑通填坑
1.数据准备:VOC2012数据集,initmodel文件夹(预训练模型),SegmentationClassAug数据2.训练部分:训练部分没什么需要改动的,也就改一下选择的配置文件。在config文件夹里有关于coco和voc数据的配置…...
Redis 做延迟消息队列
背景 看到消息队列,我们肯定会想到各种MQ,比如:RabbitMQ,acivityMQ、RocketMQ、Kafka等。 但是,当我们需要使用消息中间件的时候,并非每次都需要非常专业的消息中间件,假如我们只有一个消息队…...
刚果金FERI证书模板
FERI办理流程介(一)申请资料1:FERI APPLICATION FORM申请表格;2:草本海运提单(DRAFT B/L COPY);三:已盖章的商业发飘和箱单扫描件 (Commercial Invoice&Packing list)…...
什么是蜕变测试?
文章目录1.传统测试2.蜕变测试2.1.蜕变测试的理解2.2.蜕变测试的步骤2.2.1.生成蜕变关系2.2.2.生成蜕变用例2.2.3.执行蜕变用例2.2.4.校验蜕变关系参考文献1.传统测试 在没有蜕变测试的时代,传统软件测试的原理是:给定输入,观察被测软件的输…...
74. ‘pip‘不是内部或外部命令,也不是可运行的程序-解决办法
74. pip’不是内部或外部命令,也不是可运行的程序-解决办法 文章目录74. pip不是内部或外部命令,也不是可运行的程序-解决办法1. 课题导入2. 手动配置环境变量1. 准备工作2. 配置步骤3. 命令行安装1. 课题导入 有的同学在使用pip安装第三方库时…...
MIL图像处理那些事:应用程序模块(Mapp)- 初始化和控制MIL应用程序的执行环境
提示:本系列文章通过示例详细介绍MIL图像处理的基础知识及相关操作,让给你快速学会使用MIL进行图像处理 文章目录 前言初始化Mil环境MappAllocMappAllocDefault计时MappTimer异常处理打开和关闭 Mil 异常提示C# try...catch回调函数MappHookFunction查询MappInquire文件操作Ma…...
Pytorch基础语法学习2——argparse模块
一、基本介绍 argparse 模块是 Python 内置的用于命令行参数解析的模块,可以通过少数代码中变量或者参数的改变以实现对整个代码项目的操控。对于大型代码项目(如代码超过1000行),十分便捷 argparse 模块可以让人轻松编写用户友好的命令行接口…...
CHAPTER 2 目录及文件
目录及文件1 目录1.1 目录结构1.2 核心目录2 文件2.1 /etc/中的文件2.1.1 修改主机名(/etc/hostname)2.1.2 网卡配置文件2.1.3 开机自启动配置文件(/etc/rc.local)2.1.4 /etc/motd和/etc/issue2.2 /var/中的文件2.3 /proc/中的文件2.3.1 CPU信息(lscpu)3 文件类型3.1 类型说明3…...
2021牛客OI赛前集训营-提高组(第四场) T1最终测试
2021牛客OI赛前集训营-提高组(第四场) 题目大意 有nnn个选手参加比赛,比赛有两道题。 对于第一题,第iii个选手有50%50\%50%的可能拿到ai,1a_{i,1}ai,1分,有50%50\%50%的可能拿到000分。 对于第二题,第…...
【华为OD机试2023】租车骑绿岛 C++ Java Python
【华为OD机试2023】租车骑绿岛 C++ Java Python 前言 如果您在准备华为的面试,期间有想了解的可以私信我,我会尽可能帮您解答,也可以给您一些建议! 本文解法非最优解(即非性能最优),不能保证通过率。 Tips1:机试为ACM 模式 你的代码需要处理输入输出,input/cin接收输入…...
05-路由中的Hook
hook中使用 this.props中的路由 类组件中我们通过 this.props 获取到的关于路由的相关方法和数据,在函数组件中还是可以继续通过参数 props 来获取使用: export default function Login(prosp) {return (<button onClick{() > {props.history.pu…...
Ubuntu20.04 源码编译安装SRS-6流媒体服务器,开启GB28181支持
1. 下载SRS源码 直接从仓库clone git clone -b develop https://gitee.com/ossrs/srs.git 2. 编译源码 此处通过 --gb28181on 开启GB28181支持,默认是不开启的 cd srs/trunk && ./configure --gb28181on && make -j4 3. 编译过程中遇到的问题 …...
Web前端学习:六 -- 练习小总结
1、背景颜色透明度写法: background:rgba(R,G,B,Alpha透明度) 透明度范围:0–1,1完全不透明,0完全透明 2、伪类 hovar: 当鼠标接触该元素是,显示另一种样…...
微服务之 CAP原则
文章目录微服务CAP原则AC 可用性 一致性CP 一致性 分区容错性AP 可用性 分区容错性提示:以下是本篇文章正文内容,SpringCloud系列学习将会持续更新 微服务CAP原则 经过前面的学习,我们对 SpringCloud Netflix 以及 SpringCloud 官方整个生…...
湖南省建设银行网站/信息流广告加盟代理
公众号关注 「奇妙的 Linux 世界」设为「星标」,每天带你玩转 Linux !云原生技术里有很多技术、概念和术语,不了解的人,往往弄不清楚而一头雾水,这些概念都是啥,之间是什么关系?本文要说的就是这…...
国家备案网查询系统/济南seo的排名优化
show status;show processlist...
官方网站建设有限公司/新闻联播直播 今天
通过浏览器访问互联网上的页面,实际是把页面下载并缓存到本地电脑中。页面是有大小的,从互联网到本地电脑,就存在数据流动,从而产生了流量。例如,一个页面,有500kb大小,一次受访,则消…...
工商网站做企业公示/抖音seo怎么做的
删除 ctrl d 删除光标所在位置上的字符相当于VIM里x或者dl ctrl h 删除光标所在位置前的字符相当于VIM里hx或者dh ctrl k 删除光标后面所有字符相当于VIM里d shift$ ctrl u 删除光标前面所有字符相当于VIM里d shift^ ctrl w 删除光标前一个单词相当于VIM里db ctrl y 恢复…...
企点账户中心/网络优化工具app手机版
近日知名苹果分析师郭明錤指出苹果研发的5G基带芯片再次失败,今年下半年的iPhone14将不得不继续采用高通的5G基带芯片,此举反证华为海思研发的5G手机SOC芯片在技术方面的领先优势。苹果研发的5G芯片其实只是5G基带芯片,它此前的iPhone一直都采…...
surface go 网站开发/网站收录免费咨询
GIT分支 分支在GIT中相对较难,分支就是科幻电影里面的平行宇宙,如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,我们就需要处理一些问题了! git br…...