You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JNI中jchararray转jstring问题:Linux下仅返回首个字符

问题根源分析

你遇到的问题核心是jchar与char的编码和字节长度不匹配:

  • JNI里的jchar对应Java的char,是2字节的UTF-16编码字符
  • 你用单字节的char*数组来存储,当GetCharArrayRegion把2字节的jchar写入单字节数组时,ASCII范围内字符的高字节(通常是0)会被当成C字符串的终止符\0,导致NewStringUTF读取到第一个0就停止解析,最终只返回第一个字符。
正确的实现方案

下面提供两种针对性的解决办法,你可以根据实际需求选择:

方案1:直接用JNI函数转成jstring(最简单高效)

如果你的需求只是把jchararray转换成Java的String,完全不需要转成C的char数组,直接用NewString一步到位:

jstring JNICALL Java_YourClass_YourMethod(JNIEnv *env, jobject obj, jcharArray ch) {
    jsize length = (*env)->GetArrayLength(env, ch);
    // 获取jchar数组的指针
    jchar *jchars = (*env)->GetCharArrayElements(env, ch, NULL);
    if (jchars == NULL) {
        return NULL; // 处理内存分配失败的情况
    }
    // 直接用UTF-16的jchar数组创建jstring
    jstring result = (*env)->NewString(env, jchars, length);
    // 释放JNI资源,JNI_ABORT表示不需要把修改回写到原数组
    (*env)->ReleaseCharArrayElements(env, ch, jchars, JNI_ABORT);
    return result;
}

方案2:转成UTF-8的C字符串(适合C端需要处理字符串的场景)

如果你确实需要先得到C端的UTF-8字符串,得做编码转换,这里用iconv库实现(编译时记得加-liconv链接参数):

#include <stdlib.h>
#include <string.h>
#include <iconv.h>

jstring JNICALL Java_YourClass_YourMethod(JNIEnv *env, jobject obj, jcharArray ch) {
    jsize length = (*env)->GetArrayLength(env, ch);
    jchar *jchars = (*env)->GetCharArrayElements(env, ch, NULL);
    if (jchars == NULL) {
        return NULL;
    }

    // 预估UTF-8最大所需空间:每个UTF-16字符最多转成3字节UTF-8,加1个终止符
    size_t utf8_buf_len = length * 3 + 1;
    char *utf8_str = (char*)malloc(utf8_buf_len);
    if (utf8_str == NULL) {
        (*env)->ReleaseCharArrayElements(env, ch, jchars, JNI_ABORT);
        return NULL;
    }

    // 打开UTF-16到UTF-8的转换句柄,Java用的是大端UTF-16,对应"UTF-16BE"
    iconv_t conv_handle = iconv_open("UTF-8", "UTF-16BE");
    if (conv_handle == (iconv_t)-1) {
        free(utf8_str);
        (*env)->ReleaseCharArrayElements(env, ch, jchars, JNI_ABORT);
        return NULL;
    }

    // 执行编码转换
    char *in_ptr = (char*)jchars;
    size_t in_remaining = length * 2; // jchar是2字节,总输入字节数是length*2
    char *out_ptr = utf8_str;
    size_t out_remaining = utf8_buf_len - 1;

    if (iconv(conv_handle, &in_ptr, &in_remaining, &out_ptr, &out_remaining) == (size_t)-1) {
        iconv_close(conv_handle);
        free(utf8_str);
        (*env)->ReleaseCharArrayElements(env, ch, jchars, JNI_ABORT);
        return NULL;
    }
    *out_ptr = '\0'; // 给UTF-8字符串加终止符

    // 创建最终的jstring
    jstring result = (*env)->NewStringUTF(env, utf8_str);

    // 释放所有资源
    iconv_close(conv_handle);
    free(utf8_str);
    (*env)->ReleaseCharArrayElements(env, ch, jchars, JNI_ABORT);

    return result;
}
再聊下你的原代码问题

你的原代码里,GetCharArrayRegion是把jchar类型的元素复制到目标数组,但你传入的是char*数组,每个jchar会被拆成两个单字节写入。比如字符'a'的UTF-16编码是0x0061,写入后carr[0]是0x61(即'a'),carr[1]是0x00(即字符串终止符),NewStringUTF读到这里就认为字符串结束了,自然只返回第一个字符。

内容的提问来源于stack exchange,提问作者Anil kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:07:43