Java与C++中文字串的传递

【JNI】Java与C++中文字串的传递

  (2013-01-05 21:33:21)
标签: 

android

 

it

 

jni

 

汉字

分类: 工作随笔

JNI和C++通信中文乱码的问题

 http://developer.51cto.com/art/201112/310128.htm 

 http://blog.sina.com.cn/s/blog_a000da9d010185hr.html

首先,需要明确几个关于字符编码的基本概念:

◆  java内部是使用的16bitunicode编码(utf-16)来表示字符串的,无论英文还是中文都是2字节;

◆ jni内部是使用utf-8编码来表示字符串的,utf-8是变长编码的unicode,一般ascii字符是1字节,中文是3字节;

◆ c/c++使用的是原始数据,ascii就是一个字节,中文一般是GB2312编码,用2个字节表示一个汉字。

jni的中文字符串处理

先从字符流的方向分别对java-->C++C++-->java进行分析

◆ java-->C++

这种情况下,java调用的时候使用的是utf-16编码的字符串,jvm把这个参数传递给jniC++得到的输入是jstring,此时,可以利用jni提供的两种函数,一个是GetStringUTFChars,这个函数将得到一个UTF-8编码的字符串;另一个是GetStringChars这个将得到UTF-16编码的字符串。无论那个函数,得到的字符串如果含有中文,都需要进一步转化成GB2312的编码。

◆  c/c++ –> java

jni返回给java的字符串,c/c++首先应该负责把这个字符串变成UTF-8或者UTF-16格式,然后通过NewStringUTF或者NewString来把它封装成jstring,返回给java就可以了。

如果字符串中不含中文字符,只是标准的ascii码,那么用GetStringUTFChars/NewStringUTF就可以搞定了,因为这种情况下,UTF-8编码和ascii编码是一致的,不需要转换。

但是如果字符串中有中文字符,那么在c/c++部分进行编码转换就是一个必须了。我们需要两个转换函数,一个是把UTF8/16的编码转成GB2312;一个是把GB2312转成UTF8/16

 

下面是一个测试DEMOnative代码( NDK sampleshellojni ) : (注意红色部分代码及API)

 

 

#include <string.h>

#include <locale.h>

#include <stdlib.h>

#include <stdio.h>

#include <errno.h>

#include <android/log.h>

#include <jni.h>

 

#define LOG_TAG "hellojni_native"

 

 

#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))

#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))

 

 

 

//Java字符串的类和获取方法ID

jclass    gStringClass;

jmethodID gmidStringInit;

jmethodID gmidStringGetBytes;

 

 

int isASCII(const char * chp)

{

    char ch;

    jboolean flag= 1;

    while(ch = *chp++){

        if(ch & 0x80){

            flag = 0;

            break;

        }

    }

    return flag;

}

 

// jstring to char*

char* JstringToPchar(JNIEnv* env, jstring jstr, const char * encoding)

{

    char* rtn = NULL;

    jstring jencoding;

   

    jencoding=(*env)->NewStringUTF(env,encoding);       

    jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,jstr, gmidStringGetBytes, jencoding);   

    jsize alen = (*env)->GetArrayLength(env,barr);

    jbyte* ba = (*env)->GetByteArrayElements(env,barr, JNI_FALSE);

    if (alen > 0)

    {

        //LOGI("alen = %d ",alen);

        rtn = (char*)malloc( alen + 1);   

        memcpy(rtn, ba, alen);

        rtn[alen] = 0;

    }

    (*env)->ReleaseByteArrayElements(env,barr, ba, 0);

 

    return rtn;

}

 

//char* to jstring

jstring PcharToJstring(JNIEnv* env, const char* pchar,const char * encoding)

{

       jstring jencoding;

       jbyteArray bytes = (*env)->NewByteArray(env,strlen(pchar));

       (*env)->SetByteArrayRegion(env,bytes, 0, strlen(pchar), (jbyte*)pchar);

       jencoding = (*env)->NewStringUTF(env,encoding);

       return (jstring)(*env)->NewObject(env,gStringClass, gmidStringInit, bytes, jencoding);

}

 

jstring

Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,jobject thiz )

{

    jstring result;

 

    gStringClass= (*env)->FindClass(env,"java/lang/String");

    gmidStringGetBytes= (*env)->GetMethodID(env,gStringClass, "getBytes", "(Ljava/lang/String;)[B");

    gmidStringInit= (*env)->GetMethodID(env,gStringClass, "", "([BLjava/lang/String;)V"); 

   

    //char *myTest = "Hello from JNI !";

    char *myTest = "[华仔]Hello from JNI !";

    if(isASCII(myTest)) {

         LOGI("Is ASCII");

        result = (*env)->NewStringUTF(env, myTest);

    } 

    else{

         LOGI("Is Not ASCII");

 

        result = PcharToJstring(env,myTest,"gbk");

 

        char *outbuf;

        outbuf = JstringToPchar(env,result,"utf-8");

       

        //LOGI("strlen(outbuf) = %d",strlen(outbuf));

        //int i;

        //for(i = 0 ; i < strlen(outbuf);i++)

        //   LOGI("outbuf[%d] = %x",i,outbuf[i]);

       

        result =  (*env)->NewStringUTF(env, outbuf);

       

        if(outbuf){

        free(outbuf);

        }

    } 

 

    return result;

}

 

测试结果:

【JNI】Java与C++中文字串的传递

===end===

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值