我有一个JNI函数,它返回一个UChar数组(来自ICU4C库),我想将其转换为Java字符数组,所以我可以用Java调用它。我不确定问题出在哪里,因为每当我访问这个JNI函数时,一切都崩溃并挂起但我在任何地方都没有收到任何错误消息,包括在logcat中......很难调试!
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);
}
感谢任何帮助!
由于
答案 0 :(得分:1)
首先,我注意到你没有使用offset
- 这是一种代码味道。
其次,你没有释放UChar阵列。
第三,C函数或赋值循环可能超出数组边界。
为了帮助找到像这样的突然崩溃,我已经成功地使用了良好的print
语句与控制台一起使用。
首先,我在我的JNIGlobal类中添加了println方法:
/** 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");
}
答案 1 :(得分:1)
如果您的目的是从ICU获取UChar *值并将字符串返回给Java(我假设这是基于“来自ICU4C函数的填充str”注释),为什么不使用 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;
}
该示例当然是简化的,但应该说明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()));
}
答案 2 :(得分:0)
dstArray有多长?如果len大于dstArray.length,则c ++无法检查数组边界并愉快地破坏进程的内存。
答案 3 :(得分:0)
ICU4JNI未得到主动维护,但您可以查看它以获取从JNI调用ICU4C的示例。另请参阅ICU4JNI SVN trunk