JNI开发中unsigned char数组转jstring返回Java时长度随机异常
unsigned char数组转jstring时字符串长度随机异常问题
问题场景
Java调用共享C库的JNI开发场景中,被调用的C库函数返回unsigned char*类型结果,JNI接口需要将其转换为jstring类型返回给Java层。
异常现象
最初尝试直接强转类型后调用NewStringUTF完成转换,代码如下:
return (env)->NewStringUTF((char*) unsigned_char_array);
实际运行时,本应只有20字节有效内容的数组,返回Java层后得到的字符串长度随机为21、22甚至23字节,仅前20字节内容符合预期。
复现代码
JNIEXPORT jstring JNICALL Java_com_example_demo_DemoClass_functionToCall (JNIEnv *env, jobject, ) { // 按照库函数要求定义unsigned char数组 unsigned char unsigned_char_array[20]; // 调用库函数填充数组内容 function_to_call(unsigned_char_array); // 调试打印C端结果 printf("result : %.*s (%ld chars)\n", (int) sizeof unsigned_char_array, unsigned_char_array, (int) sizeof unsigned_char_array); // C端打印结果符合预期:输出20位数字字符串,例如92311221679609987114 // 尝试转换为jstring返回Java层 return (env)->NewStringUTF((char*) unsigned_char_array); // Java层调试获取到的字符串长度异常,为21/22/23字节不等 }

C端通过printf指定长度打印的结果完全符合预期,为20位数字字符串,但Java端获取的字符串长度始终超出20字节,且多余内容随机。
问题原因
NewStringUTF方法要求传入的是标准C风格以\0作为终止符的UTF-8字符串,定义的unsigned char unsigned_char_array[20]是固定20字节长度的栈数组,没有为字符串终止符\0预留空间,NewStringUTF读取完20字节有效内容后,会继续向后读取相邻栈内存的随机数据,直到遇到\0才停止,最终导致返回的字符串长度随机、尾部带多余乱码内容。
C端调试时printf使用了%.*s格式手动指定打印长度为20字节,不会读取数组外的内存,因此打印结果正常。
解决方案
可选择以下任意一种方式修复:
- 为数组预留终止符空间,填充完有效内容后手动追加
\0
将数组长度调整为21字节,最后1字节填充0作为字符串终止符,再调用NewStringUTF即可:unsigned char unsigned_char_array[21]; // 多分配1字节存储终止符 function_to_call(unsigned_char_array); unsigned_char_array[20] = '\0'; // 手动追加字符串终止符 return env->NewStringUTF((char*)unsigned_char_array); - 不依赖
\0终止符,使用明确长度参数构造jstring,无需修改原数组大小:
注意:如果数组存储的是UTF-8编码的多字节字符,优先使用第一种追加终止符的方案,避免出现字符截断问题;如果存储的是单字节ASCII字符(比如本场景中的纯数字内容),两种方案均可正常使用。jchar buf[20]; for (int i = 0; i < 20; i++) { buf[i] = (jchar)unsigned_char_array[i]; } return env->NewString(buf, 20); // 明确指定有效长度为20字节
内容的提问来源于stack exchange,提问作者Hyukchan Kwon
相关产品推荐
相关产品推荐

