jstring, String, char* 变换函数【转】

本文介绍如何在Java和C++中互相转换字符串。通过JNI接口实现Java字符串(jstring)到C++字符串(char*)及std::string的转换,同时也展示了从C++字符串到Java字符串(jstring)的转换方法。

#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <vcclr.h>

using namespace System;
using namespace System::Text;

// jstring To String
String^ jstringToStr(JNIEnv* env, jstring jstr)
{
    char* str = jstringTostring(env, jstr);
    String^ value = gcnew String(str);
    free(str);
    return value;
}

// jstring To char*
char* jstringTostring(JNIEnv* env, jstring jstr)
{
    char* rtn = NULL;
    jclass clsstring = env->FindClass("java/lang/String");
    jstring strencode = env->NewStringUTF("utf-8");
    jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
    jbyteArray barr = (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
    jsize alen = env->GetArrayLength(barr);
    jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
    if (alen > 0)
    {
        rtn = (char*)malloc(alen + 1);
        memcpy(rtn, ba, alen);
        rtn[alen] = 0;
    }
    env->ReleaseByteArrayElements(barr, ba, 0);
    return rtn;
}

// String To jstring
jstring strTojstring(JNIEnv* env, String^ rtn)
{
    pin_ptr<const wchar_t> wch = PtrToStringChars(rtn);
    size_t convertedChars = 0;
    size_t sizeInBytes = ((rtn->Length + 1) * 2);
    char *ch = (char *)malloc(sizeInBytes);
    errno_t err = wcstombs_s(&convertedChars,
        ch, sizeInBytes,
        wch, sizeInBytes);
    jstring js = stringTojstring(env, ch);
    free(ch);
    return js;
}

// char* To jstring
jstring stringTojstring(JNIEnv* env, const char* pat)
{
    jclass strClass = env->FindClass("Ljava/lang/String;");
    jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
    jbyteArray bytes = env->NewByteArray(strlen(pat));
    env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
    jstring encoding = env->NewStringUTF("utf-8");
    return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}

 

 

 
std::string jstring2str(JNIEnv* env, jstring jstr)
{  
    char*   rtn   =   NULL;  
    jclass   clsstring   =   env->FindClass("java/lang/String");  
    jstring   strencode   =   env->NewStringUTF("GB2312");  
    jmethodID   mid   =   env->GetMethodID(clsstring,   "getBytes",   "(Ljava/lang/String;)[B");  
    jbyteArray   barr=   (jbyteArray)env->CallObjectMethod(jstr,mid,strencode);  
    jsize   alen   =   env->GetArrayLength(barr);  
    jbyte*   ba   =   env->GetByteArrayElements(barr,JNI_FALSE);  
    if(alen   >   0)  
    {  
        rtn   =   (char*)malloc(alen+1);        
        memcpy(rtn,ba,alen);  
        rtn[alen]=0;  
    }  
    env->ReleaseByteArrayElements(barr,ba,0);  
    std::string stemp(rtn);
    free(rtn);
    return   stemp;  
}  

 

 

 

转自:http://dncsoft.iteye.com/blog/1010213

           http://www.cnblogs.com/lichien/archive/2011/10/11/2206828.html

<think>首先,用户的问题是:“我想在Android NDK开发中,使用JNI将jstring换为char*”。这涉及到JNI(Java Native Interface)在Android NDK开发中的使用。 关键点:用户想将jstring对象(在Java层传递的字符串)换为C/C++中的char*类型。 根据系统级指令: - 所有行内数学表达式必须使用$...$格式,但这里没有数学表达式,所以不需要。 - 独立公式必须使用$$...$$格式,但问题不涉及数学公式。 - LaTeX语法正确:确保任何LaTeX正确,但这里可能不需要。 - 使用中文回答。 - 生成相关问题:在回答后添加相关问题。 - 引用段落末尾添加引用标识:参考提供的引用,但用户提供了引用[^1]到[^4],我需要自然地引用它们。 用户提供的引用: - [^1]: JNI tips,包括最佳实践如存储classid/methodid,管理线程等。 - [^2]: 错误使用jstring作为char*指针的例子。 - [^3]: 关于处理空值和结构体变量的建议。 - [^4]: Android NDK Crash监控信息,包括墓碑文件和BreakPad。 用户的问题具体是jstringchar*换,所以我应该直接回答这个问题。 核心步骤: 1. 在JNI函数中,使用JNIEnv的方法来jstringchar*。 2. 使用GetStringUTFChars函数来获取UTF-8编码的字符数组。 3. 记得在使用后释放资源,以避免内存泄漏。 标准方法: - 使用env->GetStringUTFChars(jstring, NULL)来获取const char*。 - 如果需要修改,可以复制到新的char数组。 - 使用完后,调用env->ReleaseStringUTFChars(jstring, charPtr)来释放。 从引用[^2]中,它提到错误使用jstring作为char*:printf("%s", str); 这是错误的,因为jstring不是char*。所以,我必须强调正确换。 回答结构: 1. 介绍问题:在Android NDK开发中,JNI用于Java和Native代码交互。jstringJava字符串的表示,需要换为C/C++的char*。 2. 详细步骤:解释如何安全换。 3. 代码示例:提供C/C++代码片段。 4. 注意事项:包括内存管理、异常处理等。 5. 引用相关引用:自然地融入引用[^1]、[^2]等。 6. 生成相关问题:在最后添加。 确保回答真实可靠:基于JNI标准实践。 最终输出: - 使用中文。 - 清晰结构。 - 添加相关问题。 相关问题想法: 1. 如何处理JNI中的字符串编码问题? 2. JNI中如何避免内存泄漏? 3. 在Android NDK中,如何调试JNI错误? 4. 其他JNI类型换的最佳实践?</think>在Android NDK开发中,使用JNI将`jstring`换为`char*`是一个常见操作,但需谨慎处理以避免内存泄漏或编码错误。以下我将逐步解释安全换的方法,基于JNI标准实践和Android官方文档。核心是使用`JNIEnv`接口提供的函数来安全获取和释放字符串资源。 ### 步骤详解 1. **理解`jstring`类型** `jstring`是JNI中表示Java字符串的对象(对应Java的`String`类)。它不能直接用作C/C++的`char*`,因为: - `jstring`是JNI引用类型,存储Unicode编码数据。 - 直接强制换(如`(char*)str`)会导致崩溃或未定义行为,如引用[^2]所示:错误使用`printf("%s", str)`会引发`UnsatisfiedLinkError`或段错误。 2. **安全换方法** 使用`JNIEnv`的`GetStringUTFChars`函数获取UTF-8编码的`const char*`,再复制到可修改的`char*`缓冲区。步骤如下: - **获取UTF-8字符串**:调用`GetStringUTFChars`将`jstring`换为`const char*`(只读)。 - **复制到`char*`**:使用`strdup`或`malloc`复制字符串以允许修改。 - **释放资源**:必须调用`ReleaseStringUTFChars`避免内存泄漏。 - **异常处理**:检查`GetStringUTFChars`是否返回`NULL`(表示Java层抛出异常)。 3. **代码示例** 以下是一个完整的JNI函数示例,演示安全换。假设在Java层有`native void processString(String str);`方法: ```c #include <jni.h> #include <string.h> // 用于strdup JNIEXPORT void JNICALL Java_com_example_MyClass_processString(JNIEnv *env, jobject obj, jstring jstr) { // 步骤1: 检查jstring是否为NULL(避免空指针) if (jstr == NULL) { return; // 或处理错误,如引用[^3]所述,传入空值需额外验证 } // 步骤2: 获取UTF-8编码的const char*(jboolean为NULL表示不复制) const char *utfChars = env->GetStringUTFChars(jstr, NULL); if (utfChars == NULL) { return; // 内存不足或Java异常,应检查异常:env->ExceptionCheck() } // 步骤3: 复制到可修改的char*(使用strdup简化) char *cStr = strdup(utfChars); // 需在完成后手动释放cStr // 步骤4: 释放GetStringUTFChars资源(避免泄漏) env->ReleaseStringUTFChars(jstr, utfChars); // 现在可使用cStr(如打印或处理) printf("Converted string: %s\n", cStr); // 步骤5: 释放复制的缓冲区(strdup分配的内存) free(cStr); } ``` ### 关键注意事项 - **内存管理**: - `GetStringUTFChars`和`ReleaseStringUTFChars`必须成对调用,否则会导致本地内存泄漏(参考[^1]的最佳实践)。 - 使用`strdup`复制字符串后,需手动`free`,因为JNI不管理C层分配的内存。 - **编码问题**: - `GetStringUTFChars`返回UTF-8字符串,适用于大多数C库函数。如果需UTF-16,改用`GetStringChars`。 - Android中,UTF-8是推荐编码(引用[^1]提到异常和UTF处理)。 - **异常安全**: - 在`GetStringUTFChars`后调用`env->ExceptionCheck()`检测Java异常(如`OutOfMemoryError`)。 - 处理空输入:如引用[^3]强调,JNI函数不允许未处理空值,否则可能崩溃。 - **性能优化**: - 频繁调用时,避免重复换;可缓存字符串或使用全局引用(但需谨慎管理生命周期,参考[^1]的线程管理建议)。 ### 常见问题与解决方案 - **崩溃问题**:如果换后程序崩溃,检查是否忘记`ReleaseStringUTFChars`或错误释放内存。使用Android NDK的崩溃监控工具(如BreakPad解析墓碑文件,参考[^4])调试。 - **中文乱码**:确保Java字符串为UTF-8格式;必要时在C层使用`iconv`库码。 - **替代方法**: - 对于短字符串,可用`GetStringUTFRegion`直接复制到预分配缓冲区(避免动态内存分配)。 - 如果不需要修改字符串,直接使用`const char*`而不复制。 通过以上方法,您可以安全高效地实现换。更多JNI最佳实践可参考Android官方文档[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值