JNI调用将jstring转换为char *

时间:2013-12-12 06:13:08

标签: android c++ java-native-interface

我的cpp代码包含一个我希望转换为const char *的jni函数。这是我正在使用的代码

extern "C" {
void Java_com_sek_test_JNITest_printSomething(JNIEnv * env, jclass cl, jstring str) {

    const char* mystring = env->GetStringUTFChars(env, str, 0);
    PingoScreen::notify();
}

我收到错误

no matching function for call to '_JNIEnv::GetStringUTFChars(JNIEnv*&, _jstring*&, int)

我做错了什么?

3 个答案:

答案 0 :(得分:4)

对于您的代码和方法,有几件事情并不完全正确:

  1. 正如您所发现的那样,(env*)->JNIFunc(env,...)在C ++中应该是env->JNIFunc(...)。您的供应商(Google Android)jni.h简化了C语法的C ++语法。
  2. 您没有调用与“固定”功能(GetStringUTFChars)对应的“Release”功能(ReleaseStringUTFChars)。这非常重要,因为固定对象会降低JVM垃圾收集器的内存效率。
  3. 你误解了GetStringUTFChars的最后一个论点。它是输出参数的指针。结果不是很有趣所以通过nullptr
  4. 您正在使用处理已修改的 UTF-8编码(GetStringUTFChars等)的JNI函数。应该没有必要使用该编码。 Java类非常有能力转换编码。它们还可以控制无法在目标编码中编码字符时发生的情况。 (默认是将其转换为?。)
  5. 将JVM对象引用(jstring)转换为指向一个字节存储(char*)的想法需要大量改进。您可能希望使用特定或OS默认编码将JVM java.lang.String中的字符复制到“本机”字符串。 Java字符串具有UTF-16编码的Unicode字符。 Android通常使用带有UTF-8编码的Unicode字符集。如果您还需要其他内容,可以使用Charset对象指定它。
  6. 此外,在C ++中,使用STL std::string来保存字符串的计数字节序列会更方便。如果需要,您可以从std::string获得a pointer to a null-terminated buffer
  7. 请务必阅读Android的JNI Tips

    以下是您的函数的一个实现,它允许供应商的JVM实现选择目标编码(适用于Android的UTF-8):

    extern "C" JNIEXPORT void Java_com_sek_test_JNITest_printSomething
      (JNIEnv * env, jclass cl, jstring str) {
        // TODO check for JVM exceptions where appropriate 
    
        //  javap -s -public java.lang.String | egrep -A 2 "getBytes"
        const auto stringClass = env->FindClass("java/lang/String");
        const auto getBytes = env->GetMethodID(stringClass, "getBytes", "()[B");
    
        const auto stringJbytes = (jbyteArray) env->CallObjectMethod(str, getBytes);
    
        const auto length = env->GetArrayLength(stringJbytes);
        const auto pBytes = env->GetByteArrayElements(stringJbytes, nullptr); 
        std::string s((char *)pBytes, length);
        env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);   
    
        const auto pChars = s.c_str(); // if you really do need a pointer
    }
    

    但是,我可能会在Java端调用String.getBytes,定义采用字节数组而不是字符串的本机方法。

    (当然,使用GetStringUTFChars的实现确实适用于Unicode字符串的某些子集,但为什么会施加深奥和不必要的限制?)

答案 1 :(得分:2)

根据文件,

GetStringUTFChars const jbyte * GetStringUTFChars(JNIEnv * env,jstring string, jboolean * isCopy);

返回一个指向字节数组的指针,该字节数组表示修改后的UTF-8编码中的字符串。此数组在ReleaseStringUTFChars()发布之前有效。

如果isCopy不为NULL,则如果进行了复制,则* isCopy设置为JNI_TRUE;如果没有复制,则设置为JNI_FALSE。

所以最后一个参数应该是一个jboolean;

答案 2 :(得分:1)

尝试...更改此行

const char* mystring = env->GetStringUTFChars(env, str, 0);

const char *mystring = (*env)->GetStringUTFChars(env, str, 0);

希望它有效:)