JNI使用时,需要传递中文,遇到乱码问题,多次尝试失败。遂仔细研究了下编码格式。
首先,需要明确几个关于字符编码的基本概念:
◆ java内部是使用的16bit的unicode编码(utf-16)来表示字符串的,无论英文还是中文都是2字节;
◆ jni内部是使用utf-8编码来表示字符串的,utf-8是变长编码的unicode,一般ascii字符是1字节,中文是3字节;
◆ c/c++使用的是原始数据,ascii就是一个字节,中文一般是GB2312编码,用2个字节表示一个汉字。

C语言中的汉字传递到java端

先来实现C语言中的汉字传递到java端,有两种方案:

  • 1,在C端以字节传送到java端,在java中转换;
  • 2,在C端就转换好。

下面来详细说明:

1,在C端以字节传送到java端,在java中转换编码格式;

在C中,将char*转换为jbyteArray,然后设置数据:

jbyteArray byteArray = env->NewByteArray(strlen(str));
env->SetByteArrayRegion(byteArray,0,strlen(str),(jbyte *)str);

在Java端,获取数组,然后从”gb2312”格式生成utf16格式的java字符串:

byte[] byteArray = JniClient.getChineseByteArray();
strSayHello = new String(byteArray,"gb2312");

2,在C端就转换好编码格式

步骤要复杂一些,核心还是一样的,是在C端通过jni访问java的String创建方法,进行编码格式转换。

jstring CStr2Jstring(JNIEnv*   env,   char* buf)
{jclass Class_string;jmethodID mid_String, mid_getBytes;jbyteArray bytes;jbyte* log_utf8;jstring codetype, jstr;Class_string = env->FindClass( "java/lang/String"); //获取class//先将gbk字符串转为java里的string格式mid_String = env->GetMethodID( Class_string, "<init>","([BLjava/lang/String;)V");int len=strlen(buf)+1;//需要加1,把字符串的结束符也包含进来bytes = env->NewByteArray( len);env->SetByteArrayRegion( bytes, 0, len, (jbyte*) buf);codetype = env->NewStringUTF( "gbk");jstr = (jstring)env->NewObject( Class_string, mid_String, bytes, codetype);env->DeleteLocalRef( bytes);//再将string变utf-8字符串。mid_getBytes = env->GetMethodID( Class_string, "getBytes",  "(Ljava/lang/String;)[B");codetype = env->NewStringUTF( "utf-8");bytes = (jbyteArray)env->CallObjectMethod( jstr, mid_getBytes, codetype);log_utf8 = env->GetByteArrayElements( bytes, JNI_FALSE);return env->NewStringUTF((char *)log_utf8);
}

java中的汉字传递到C端

下面来实现java中的汉字传递到C端,也是两种方案:

  • 1,在Java端就转换好编码格式。
  • 2,java端只传递,在C端转换;

下面来详细说明:

1,在Java端就转换好编码格式

在Java中,将String转换为”gbk”格式的byte[]:

String strToJNI = "欢迎";
byte[] byteArr = new byte[strToJNI.length()*2];
byteArr=strToJNI.getBytes("gbk");

在C中,获取jbyteArray的起始地址,当成char*的地址访问即可:

jbyte * byteArr=env->GetByteArrayElements(byteArray,0);
char * buf = (char *)byteArr;

2,java端只传递,在C端转换;

在C语言中做编码格式的转换,步骤要复杂一些,但是核心思想还是一样的,就是在C端通过jni访问java的String创建方法,进行编码格式转换。

char*   Jstring2CStr(JNIEnv*   env,   jstring   jstr)
{char*   rtn   =   NULL;jclass   clsstring   =   env->FindClass("java/lang/String");//寻找 java里面String.classjstring   strencode   =   env->NewStringUTF("GB2312");//创建java字符串 "gb2312"jmethodID   mid   =   env->GetMethodID(clsstring,   "getBytes",   "(Ljava/lang/String;)[B");//寻找到java String getbytes();jbyteArray   barr=   (jbyteArray)env->CallObjectMethod(jstr,mid,strencode); // String .getByte("GB2312");jsize   alen   =   env->GetArrayLength(barr); //获取长度jbyte*   ba   =   env->GetByteArrayElements(barr,JNI_FALSE); //jbyteArray转为jbyte*if(alen   >   0){rtn   =   (char*)malloc(alen+1);         //"\0"memcpy(rtn,ba,alen);rtn[alen]=0;}env->ReleaseByteArrayElements(barr,ba,0);  //释放掉return rtn;
}

总结

1,优先选择在java端做字符编码格式的转换

通过上面的介绍,我们可以看出,在Java端实现编码格式的转换,代码更简洁,也更易于理解。所以,我们应该优先选择在java端做字符编码格式的转换。

2,C中字符串的长度

在C中向外传递时需要加1,将结束符传递出来(见CStr2Jstring())。否则,后面不知道会跟着什么随机数据的。
在java向C传递的byte数组,逐字节打印数组内容,数组的长度不能使用strlen(buf)(见SetChineseByteArray())。
传递的是byte数组,而不是字符串,所以这个长度不能使用strlen,而是需要调用env->GetArrayLength(byteArray)来获取。

3,C中的char类型

在C语言中调用日志打印函数,中文打印为乱码。
我是通过打印具体字节数据来验证传递成功的。
打印语句如下:

LOGI( "log: buf[%d]=%d",i,*(signed char *)(buf+i));

为何要强制转换为 signed char 呢?
我之前未使用强制转换时,打印出来的数据,并不一致,如下:
06-26 16:35:50.220: I/Hello(4529): log: byteArr[0]=-60
06-26 16:35:50.220: I/logfromc(4529): log: buf[0]=196
这两个数据有差异的原因在于:java中的byte,取值范围为[-128,127]。
在ARM平台上,C语言中的char的取值范围[0,255],也就是说,arm上的char是无符号的。通过计算:-60=196-256,可以知道值是匹配的。但是这样靠人脑计算比较累,所以就让电脑干啦(强制转换成 signed char)。
通常我们的手机的cpu都是ARM,例如我的手机就是arm啦,所以用char类型打印出来的值是不同的。
在模拟器上测试,C语言中的char是有符号的,取值范围[-128,127],因为模拟器是在PC上跑的,PC是x86平台。
char是有点特殊的啦,在不同平台上编译出来的情况,有所不同,可要注意哦。

demo下载:

http://download.csdn.net/detail/lintax/9560249

Android JNI 中文字符传递相关推荐

  1. android java调用参数,如何从命令行调用Android JNI函数并传递Java对象参数

    一.前言 当我们对某个使用原生库(native library)的恶意软件或者应用进行分析或渗透测试时,如果能够对库函数进行隔离和执行是再好不过的事情,这样做我们就可以使用其自身的代码来调试对抗恶意软 ...

  2. jni 传递字符串到java_Android JNI开发-java与c++其间的中文字符串传递

    Android JNI开发---java与c++之间的中文字符串传递 最近在做一个Android电子词典,其中在从词库中读取词条时,用到了jni---java调用c++;在java代码里调用本地方法时 ...

  3. 网页编码与数据传递中的中文字符编码

    最近工作中遇到中文编码,中文参数传递,AJAX返回值包含中文乱码的问题,为此奋斗了一宿,有点心得,有点体会,总结如下,希望对迷惑于此中者有解惑之功效! 在网上一阵狠搜,编码函数的确是有,包括Javas ...

  4. android 4.4.3上面,联系人的头像默认显示首字母,但是不支持中文字符,修改支持中文

    在android 4.4.3上面,联系人的头像默认显示首字母,但是不支持中文字符,如下图: 如果联系人名字的第一位是英文字符(a-z || A-Z),则默认头像将显示该首字母. 如果支持中文时显示第一 ...

  5. android 判断是否是标点符号_Java 中文字符判断 中文标点符号判断

    Java Character 实现Unicode字符集介绍  CJK中文字符和中文标点判断 主要内容: 1. Java Character类介绍: 2. Unicode 简介及 UnicodeBloc ...

  6. android怎样判断中文字符,android 判断字符串中英文

    // 判断一个 char 是否是中文字符(CJK 分别代表中文.日文.韩文) public static boolean isChinese(char c) { Character.UnicodeBl ...

  7. android jni jstring 转 char*

    今天,简单讲讲Android jni如何将java的Sring转成char*. 这个之前一直不理解,所以我都是android传入byte[]转成char*,有一篇博客专门讲了这个.后来发现用Strin ...

  8. Android JNI学习(四)——JNI的常用方法的API

    前三篇主要讲解了jni基础相关的理论知识,今天主要讲解一下JNI的常用方法的API,掌握了基本的理论知识和常用的API接下来才能更好的实战. jni的常用API大纲 再看API前,我建议大家主要结合官 ...

  9. android post json格式,Android中post请求传递json数据给服务端的实例

    在最近的项目中有个需求是这样的: 入参封装成JSON,EXAMPLE: { "uuid": "iamauuid","clientType": ...

最新文章

  1. php+微信开发+解绑,微信开发之解绑设备通知的方法
  2. 通过 Visual Studio 的“代码度量值”来改进代码质量
  3. 无限序列 (ybtoj C.3)
  4. 基于linux环境采用update-alternatives 方式进行python版本切换
  5. 揭秘大流量场景下发布如「丝般顺滑」背后的原因
  6. Aliyun Serverless VSCode Extension 上架并开源
  7. ajax 异步插入图片到数据库(多图上传)
  8. tar包在linux下 java安装
  9. 开始研究WEKA,一个开源java的数据挖掘工具
  10. Socket编程之TCP实例(附C/C++代码详解)
  11. 垃圾代码评析——关于《C程序设计伴侣》9.4——链表(一)
  12. warning: mysql-community-libs-5.7.11-1.el7.x86_64.rpm: Header V3 DSA/SHA1 Signature, key ID 5072e1f5
  13. SQLServer数据库基础教程
  14. 如何写出一份好的解决方案
  15. Java是什么?Java到底能干嘛?
  16. 银行卡四要素验证补充测试
  17. MATLAB 线性拟合
  18. matplotlib交互式数据光标实现——mplcursors
  19. 华为P30销量破千万有多少含金量?
  20. 利用python分析电商_Python电商数据分析实战

热门文章

  1. 启用计算机的无线同屏,完美:将计算机转换为无线显示器,Windows 10的此功能确实强大...
  2. 解决win10笔记本内置麦克风不能用的历程和方法
  3. PID控制------伯德图原理
  4. TSN(temporal segment networks)环境配置
  5. 晶体三极管的结构和符号
  6. 用于大数据的星际文件系统
  7. c语言程序设计教程南京大学出版社答案,《新编C语言程序设计教程》习题解答与实验指导...
  8. 基于单片机定时闹钟设计
  9. MT8516处理器简介—MT8516芯片技术资料解析
  10. 关于Wrap Lighting与皮肤SSS