2013-12-12 40 views
1

我的cpp代碼包含一個jni函數,我希望將其轉換爲const char *。這是我使用JNI調用將jstring轉換爲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) 

我到底做錯了什麼?

回答

2

根據該文件,

GetStringUTFChars 常量jbyte * GetStringUTFChars (JNIEnv * env,jstring字符串, jboolean * isCopy);

返回指向表示修改的UTF-8編碼中的字符串的字節數組的指針。這個數組在ReleaseStringUTFChars()釋放之前一直有效。

如果isCopy不是NULL,那麼* isCopy設置爲JNI_TRUE,如果有副本;或者如果沒有複製,它被設置爲JNI_FALSE。

所以最後一個參數應該是一個jboolean;

+0

仍然劑量工作 – AndroidDev

+0

刪除第一個參數,然後重試。我也有一些有這種方法的jni代碼。它只有兩個參數。這些是jstring字符串,jboolean * isCopy – Shashika

+3

感謝這工作。 const char * mystring = env-> GetStringUTFChars(str,JNI_FALSE); – AndroidDev

1

嘗試...更改此行

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

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

希望工程:)

+0

我得到一個錯誤「的基礎標識符‘ - >’具有非指針型'JNIEnv {aka _JNIEnv}'「 – AndroidDev

4

有幾件事情是不是你的代碼和做法完全正確:

  1. 正如你已經發現,(env*)->JNIFunc(env,...)應該在C++ env->JNIFunc(...)。您的供應商(Google Android's)jni.h通過C語法簡化了C++語法。
  2. 您沒有調用與「pinning」函數(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

請務必閱讀Android的JNI Tips

這是你的功能的實現,讓供應商的JVM實現,選擇目標編碼(這是UTF-8爲Android):

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 
} 

不過,我可能會做調用String.getBytes上Java方面,定義本地方法取一個字節數組而不是一個字符串。

(當然,使用GetStringUTFChars實現做工作的Unicode字符串的某個子集,但爲什麼強加一個深奧的和不必要的限制嗎?)