0

我有一个 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);

}

任何帮助表示赞赏!

谢谢

4

4 回答 4

1

JNI 可能是一个真正令人头疼的问题。从表面上看,你的功能看起来不错。

首先,我注意到您没有使用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");
}
于 2011-02-23T18:47:13.237 回答
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()));
}
于 2012-06-20T02:51:05.600 回答
0

dstArray 有多长?如果 len 大于 dstArray.length,c++ 无法检查数组边界并愉快地破坏进程的内存。

于 2011-02-15T21:13:10.177 回答
0

ICU4JNI没有得到积极维护,但您可以查看它作为从 JNI 调用 ICU4C 的示例。另见ICU4JNI SVN 主干

于 2011-02-23T18:21:55.317 回答