java的jni 为Java和c/c++语言间的通信提供了统一的接口。在两种语言的字符串转换方面,我搜了搜,发现很多都是人云亦云。如果不是因为做项目遇到遗留的bug,恐怕我也人云亦云了。
先看一下 jchar的定义
typedef unsigned short jchar; /* unsigned 16 bits */
是一个无符号端整型,而不是wchar_t。(参考jni.h,这文件在Android NDK里面,搜索就能找到)
为了兼容早期的jvm ,java使用16比特(两字节)表示一个小于65535的UNICODE码,用代理对的形式表示其他UNICODE码(关于代理对,http://zh.wikipedia.org/zh-cn/UTF-16)
而将UNICODE编码时,若使用变种UTF8,java会把字节 00 变为 0xC0 80,编码代理对更复杂(http://zh.wikipedia.org/wiki/UTF-8)。
好了,有了以上的认识,在使用JNI的一些接口时就要注意了
jstring 到 c/c++字符串
应从 jchar 到 wchar_t 的转换,而不是jchar 到 char。也就是在转换时,要保持jstring的每个jchar的值不变。
JNIEnv *env = 获取相关句柄;
jstring jstr = java字符串;
//获取java字符串的长度
jsize jstr_len = env->GetStringLength(jstr);
//获取java字符串的jchar指针
const jchar * pjstr = env->GetStringChars(jstr);
//申请c字符串的内存空间
wchar_t *pcstr = new wchar_t[jstr_len];//通常 sizeof(wchar_t)不小于2,若为1,应考虑使用其他类型来容纳jchar
//或者
std::wstring wstr;
wstr.assign(jstr_len,0);
//复制
jstr_len --;
while( jstr_len > -1 )
{
pcstr[jstr_len ] = pjstr[jstr_len];
//或者
wstr[jstr_len] = pjstr[jstr_len];
jstr_len -- ;
}
上面代码使用了GetStringChars而不是GetStringUTFChars。之所以这样做,就是为了保持java字符串到c/c++字符串的无损转换。
不过,仍然要注意一个问题,就00字节的处理,建议使用c++的wstring类。
如果:
1、jstring的每一个jchar都在[1,127]内
2、或者,你需要做UTF8转换但是不关心GetStringUTFChars采用变种UTF8还是标准UTF8,也不关心可逆转换
可以使用GetStringUTFChars。