2013-06-05 37 views
8

Có cần phải chuyển đổi char * thành jbyteArray, sau đó gọi hàm xâu chuỗi của java để tạo ra một chuỗi không? Làm thế nào khác nó có thể được thực hiện? Hãy giúp tôi.Chuyển đổi char * thành jstring trong JNI, khi char * được truyền bằng cách sử dụng va_arg

static int testhandler(void *arg, ...) 
{ 
    int i; 
    struct callback *cb = (struct callback *)arg; 

    JNIEnv *env = cb->env; 
    char *sig = cb->signature; 

    jint size = (jint) strlen(sig); 
    jint size1; 
    va_list arguments; 

    jobjectArray return_array; 
    jclass obj_class; 
    jbyteArray bytes; 
    jstring str; 

    obj_class = (*env)->FindClass(env, "java/lang/Object"); 
    return_array = (*env)->NewObjectArray(env, size, obj_class, NULL); 

    va_start(arguments, arg); 

    for (i = 0; i < size; i++) { 
     jclass clazz; 
     jmethodID id; 
     jobject obj; 
     jobject encoding; 
     switch (sig[i]) { 
      case 'i': { 
       clazz = (*env)->FindClass(env, "java/lang/Integer"); 
       id = (*env)->GetMethodID(env, clazz, "<init>", "(I)V"); 
       obj = (*env)->NewObject(env, clazz, id, va_arg(arguments, uint32_t)); 
       (*env)->SetObjectArrayElement(env, return_array, i, obj); 
       break; 
      } 
      case 'l': { 
       clazz = (*env)->FindClass(env, "java/lang/Long"); 
       id = (*env)->GetMethodID(env, clazz, "<init>", "(J)V"); 
       obj = (*env)->NewObject(env, clazz, id, va_arg(arguments, uint64_t)); 
       (*env)->SetObjectArrayElement(env, return_array, i, obj); 
       break; 
      } 
      case 's': { 
       clazz = (*env)->FindClass(env, "java/lang/String"); 
       size1 = (jint) strlen(va_arg(arguments, char *)); 
       id = (*env)->GetMethodID(env, clazz, "<init>", "([BLjava/lang/String;)V"); 

       encoding = (*env)->NewStringUTF(env, va_arg(arguments, char *)); 
       bytes = (*env)->NewByteArray(env, size1); 
       (*env)->SetByteArrayRegion(env, bytes, 0, size1, (jbyte *)(va_arg(arguments, char *))); 

       str = (jstring)(*env)->NewObject(env, clazz, id , bytes); 
       obj = (*env)->NewObject(env, clazz, id, str); 
       (*env)->SetObjectArrayElement(env, return_array, i, obj); 
       break; 
      } 
      default: { 
       printf("unknown signature char '%c'\n", sig[i]); 
      } 
     } 

    } 
    va_end(arguments); 
    (*env)->CallVoidMethod(env, cb->handler, cb->id, return_array); 

    return 0; 
} 
+0

Thứ nhất, tôi không hiểu, tại sao khi 'env' có kiểu' JNIEnv * 'уоu viết' (* env) -> SomeFunc'? Mã này có biên dịch không? Thứ hai, chọn một trong các biến thể sau: hướng đối tượng: 'env-> SomeFunc (params)' hoặc Kiểu C: 'SomeFunc (env, params)'. –

+3

@TsarIoann Anh ấy đang sử dụng kiểu C. Nó là "hướng đối tượng" C, nơi bạn phải sử dụng '(* env) -> SomeFunc (env, xyz)'. Nó hoàn toàn chính xác: http://stackoverflow.com/a/936148/1350762 – maba

+0

@maba Oh my god. Lấy làm tiếc. Câu trả lời được đưa ra bởi mkaes là chính xác. –

Trả lời

31

Bạn chỉ có thể kiểm tra tài liệu JNI api. Ví dụ. Here.
Bạn sẽ tìm thấy:

jstring NewStringUTF(JNIEnv *env, const char *bytes); 

Vì vậy, tất cả các bạn phải làm điều đó một cái gì đó như thế này:

char *buf = (char*)malloc(10); 
strcpy(buf, "123456789"); // with the null terminator the string adds up to 10 bytes 
jstring jstrBuf = (*env)->NewStringUTF(env, buf); 
+0

Có cần thiết 'free (buf)' tại một số điểm hay không 'NewStringUTF' làm cho JVM chịu trách nhiệm về bộ nhớ đó? – zmb

+0

@zmd: Có, bạn phải tự giải phóng bộ nhớ. Và tùy thuộc vào ngữ cảnh, bạn cũng có thể cần phải gọi 'DeleteLocalRef()' trên đối tượng chuỗi của bạn. – mkaes

+0

typo, '' (* env) -> NewStringUTF (env, buf); '' phải là '' env-> NewStringUTF (env, buf); ''. – Yuanhang

6

Nó phụ thuộc vào bản chất của char * chuỗi của bạn. NewStringUTF bản sao từ mã hóa 0-chấm dứt, được sửa đổi UTF-8 của các ký tự Unicode. NewString các bản sao từ mã hóa được tính, UTF-16 của các ký tự Unicode. Nếu bạn không có một trong số đó, bạn phải thực hiện chuyển đổi.

Rất nhiều mã sử dụng NewStringUTF được viết với giả định rằng chuỗi là NUL-chấm dứt ASCII. Nếu giả định đó là chính xác thì nó sẽ hoạt động vì mã hóa UTF-8 đã sửa đổi và mã hóa ASCII sẽ tạo ra cùng một chuỗi byte. Mã như vậy nên được nhận xét rõ ràng để ghi lại hạn chế về dữ liệu chuỗi.

Phương pháp chuyển đổi mà bạn ám chỉ — gọi hàm Java (ví dụ: String(byte[] bytes, Charset charset)) —là một cách tốt nhất. Một thay thế (trong Windows, tôi thấy bạn đang sử dụng Visual Studio) là MultiByteToWideChar. Một lựa chọn khác là iconv.

Dòng dưới cùng: Bạn phải biết những gì character set and encoding sử dụng chuỗi và sau đó chuyển đổi nó thành mã Unicode UTF-16 để sử dụng làm chuỗi Java.

3

nó là tốt hơn để trở byte[] để java chứ không phải jstring do sự khác biệt giữa chuỗi UTF trong java và c string.it dễ dàng hơn nhiều để đối phó vấn đề mã hóa trong java

trong java:

byte[] otherString = nativeMethod("javastring".getBytes("UTF-8")) 

trong C++:

jbyte* javaStringByte = env->GetByteArrayElements(javaStringByteArray, NULL); 
jsize javaStringlen = env->GetArrayLength(javaStringByteArray); 
std::vector<char> vjavaString; 
vjavaString.assign(javaStringByte , javaStringByte + tokenlen); 
std::string cString(vjavaString.begin(), vjavaString.end()); 
// 
// do your stuff .. 
// 
jsize otherLen = otherCString.size(); 
jbyteArray otherJavaString = env->NewByteArray(otherLen); 
env->SetByteArrayRegion(otherJavaString , 0, otherLen , (jbyte*) &otherJavaString [0]); 

env->ReleaseByteArrayElements(javaStringByteArray, javaStringByte , JNI_ABORT); 
return otherJavaString ; 

trong java nữa:

new String(otherString); 
+0

có bất kỳ sự khác biệt đáng chú ý nào nếu tôi trả về chuỗi thay vì byte [] bạn đã đề xuất không? –

+1

không, không phải vậy. kể từ khi tôi không quen thuộc với jstring và nó liên quan đến api, sử dụng byte [] chỉ là để thuận tiện – zyanlu

Các vấn đề liên quan