2011-02-15 110 views
0

我有一個JNI函數,它返回一個UChar數組(來自ICU4C庫),我想將它轉換爲Java字符數組,以便可以從Java調用此函數。我不知道問題出在哪裏,因爲每當我訪問這個JNI函數時,一切都崩潰並掛起,但我不會在任何地方發現錯誤消息,包括logcat中......非常難以調試!JNI - 映射UChar類型爲

UChar數組可以直接映射到jcharArray類型嗎?另外,我可以使用它作爲返回類型嗎?或者我可以將它作爲JNI函數填充的參數傳入?

下面是基本上我試圖做一個片段:

static jint testFunction(JNIEnv* env, jclass c, jobject obj, jcharArray chsArray, 
          int offset, int len, jcharArray dstArray) { 

jchar* dst = env->GetCharArrayElements(dstArray, NULL); 

if (dst != NULL) { 

    UChar *str = new UChar[len]; 

    //populate str here from an ICU4C function 

    for (int i=0; i<len; i++) 
     dst[i] = str[i];  //this might be the problematic piece of code (can I issue an assignment like this?) 
    } 
} 

env->ReleaseCharArrayElements(dstArray, dst, 0); 

} 

任何幫助表示讚賞!

謝謝

+1

您已經嘗試了調試器附加到正在運行的Java程序調用JNI代碼,把一個斷點在第一行,並通過它一步? – 2011-02-15 20:40:27

回答

1

JNI可能是一個真正的頭痛。你的表面看起來很好看。

首先,我注意到你沒有使用offset - 這是一種代碼味道。

其次,你沒有釋放UChar陣列。

第三,C函數或賦值循環可能會溢出數組邊界。


爲了幫助定位突然崩潰這樣的,我已經成功地與控制檯一起使用的好醇派print聲明。

首先我添加一個println方法我JNIGlobal類:

/** Print text or ASCII byte array prefixed with "JNI: ". Primarily for native code to output to the Java console. */ 
static public void println(Object val) { 
    if(val instanceof byte[]) { byte[] ba=(byte[])val; val=new String(ba,0,ba.length); } 
    System.out.println("JNI: "+val); 
    } 

然後,我添加一個對應方法我的C代碼:

void println(JNIEnv *jep, byte *format,...) { 
    va_list        vap; 
    byte        txt[5001]; 
    jsize        txtlen; 
    jclass        eCls; 
    jint        mId; 
    jbyteArray       jText; 

    va_start(vap,format); vsprintf(txt,format,vap); va_end(vap); 
    txtlen=(long)strlen(txt); 

    if((eCls=(*jep)->FindClass(jep,"<your/package/here/JNIGlobal"))==0) { 
     printf("JNI: Global class not found (Error Text: %s)\n",txt); 
     return; /* give up */ 
     } 
    if((mId=(*jep)->GetStaticMethodID(jep,eCls,"println","(Ljava/lang/Object;)V"))==0) { 
     printf("JNI: Global println method not found (Error Text: %s)\n",txt); 
     return; /* give up */ 
     } 
    jText=(*jep)->NewByteArray(jep,txtlen); 
    (*jep)->SetByteArrayRegion(jep,jText,0,txtlen,(void*)txt); 
    (*jep)->CallStaticVoidMethod(jep,eCls,mId,jText); 
    } 

然後我打電話println(env,"Some formatted output")在每一行來源看它有多遠。在我的環境(一個AS/400)中,當JVM在交互式運行期間崩潰時,我只剩下控制檯 - 您可能希望在Java代碼中添加一小段延遲,以確保在控制檯消失之前看到輸出。

因此,對於你,就像這樣:

static jint testFunction(JNIEnv* env, jclass c, jobject obj, 
jcharArray chsArray, int offset, int len, jcharArray dstArray) { 

/**/println("** testFunction 1"); 
    jchar* dst = env->GetCharArrayElements(dstArray, NULL); 

/**/println("** testFunction 2"); 
    if (dst != NULL) { 
/**/println("** testFunction 3"); 
     UChar *str = new UChar[len]; 
/**/println("** testFunction 4"); 

     //populate str here from an ICU4C function 

/**/println("** testFunction 5"); 
     for (int i=0; i<len; i++) 
      dst[i] = str[i];  //this might be the problematic piece of code (can I issue an assignment like this?) 
     } 
/**/println("** testFunction 6"); 
    } 

    env->ReleaseCharArrayElements(dstArray, dst, 0); 
/**/println("** testFunction 7"); 
} 
0

dstArray有多長?如果len大於dstArray.length,C++將無法檢查數組邊界並高興地破壞進程的內存。

0

ICU4JNI沒有被主動維護,但是你可能會看到它的一個從JNI調用ICU4C的例子。另請參閱ICU4JNI SVN trunk

1

如果你的目的是爲了得到一個ICU UCHAR *值,並返回一個字符串到Java(我基於「填充海峽從這裏假定這ICU4C功能「評論),爲什麼不只是使用jstring

例如:

jstring Java_com_mysomethingsomething_test_getAString(JNIEnv* env, jobject thiz) 
{ 
    UChar* buf = new UChar[BUF_LEN]; 
    int32_t len; 
    PouplateBuffer(buf, &len);  //populate str here from an ICU4C function 
    jstring result = env->NewString(reinterpret_cast<jchar*>(buf), static_cast<jint>(len)); 
    delete [] buf; 
    return result; 
} 

該示例simplifed當然,但應說明UCHAR *到的jstring轉換。這也很容易用的UnicodeString工作:

jstring Java_com_mysomethingsomething_test_getAString(JNIEnv* env, jobject thiz) 
{ 
    const UnicodeString result = PopulateString(); 
    return env->NewString(reinterpret_cast<jchar*>(result.getBuffer()), static_cast<jint>(result.length())); 
}