JNI调用将jstring转换为char*

JNI call convert jstring to char*

本文关键字:char 转换 jstring 调用 JNI      更新时间:2023-10-16

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

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)

我做错了什么?

您的代码和方法有几点不太正确:

  1. 正如您所发现的,(env*)->JNIFunc(env,...)应该是C++中的env->JNIFunc(...)。您的供应商(Google Android的)jni.h简化了C++语法而不是C语法
  2. 您没有调用与"钉扎"函数(GetStringUTFChars)相对应的"Release"函数(ReleaseStringUTFChar)。这一点非常重要,因为固定对象降低了JVM垃圾收集器的内存效率
  3. 你误解了GetStringUTFChars的最后论点。它是一个输出参数的指针。结果不是很有趣,所以通过nullptr
  4. 您使用的JNI函数处理修改的UTF-8编码(GetStringUTFChars等人)。应该没有必要使用这种编码。Java类非常能够转换编码。它们还让您可以控制当无法在目标编码中对角色进行编码时会发生什么。(默认情况是将其转换为?。)
  5. 将JVM对象引用(jstring)转换为指向单字节存储(char*)的指针的想法需要大量改进。您可能希望使用特定或操作系统默认编码将JVM java.lang.String中的字符复制到"本机"字符串。Java字符串包含使用UTF-16编码的Unicode字符。Android通常使用Unicode字符集和UTF-8编码。如果您需要其他东西,可以使用Charset对象指定它
  6. 此外,在C++中,使用STL std::string来保存字符串的计数字节序列更方便。如果需要的话,您可以从std::string中获取一个指向空终止缓冲区的指针

请务必阅读Android的JNI提示。

以下是您的函数的实现,它允许供应商的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字符串的某些子集,但为什么要施加一个深奥而不必要的限制?)

根据文档,

GetStringUTFCharsconst jbyte*GetStringUTFChars(JNIEnv*env,jboolean*isCopy);

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

如果isCopy不为NULL,则如果进行了复制,则*isCopy设置为JNI_TRUE;或者如果没有进行复制则将其设置为JNI_ FALSE。

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

尝试。。。更改此行

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

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

希望它能起作用:)