JNI - отображение типа UChar на - PullRequest
0 голосов
/ 15 февраля 2011

У меня есть функция 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 ]

1 голос
/ 20 июня 2012

Если ваше намерение состоит в том, чтобы получить значение UChar * из ICU и вернуть строку в 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;
}

Этот пример, конечно, упрощен, но должен проиллюстрировать преобразование 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()));
}
1 голос
/ 23 февраля 2011

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 голосов
/ 23 февраля 2011

ICU4JNI активно не поддерживается, но вы можете посмотреть на пример вызова ICU4C из JNI. См. Также ICU4JNI SVN транк

0 голосов
/ 16 февраля 2011

Сколько времени занимает dstArray?C ++ не может проверять границы массива и счастливо портит память вашего процесса, если len больше, чем dstArray.length.

...