2013-08-19 15 views
5

Nella documentazione della funzione JNI FindClass posso leggere su argomento nome:stringhe JNI e stringhe C

nome: il nome completo della classe (...) La stringa è codificato in modificata UTF-8.

Secondo la documentazione modificato UTF-8 deve terminare con doppi '\ 0' caratteri:

il carattere nullo (char) 0 è codificato utilizzando il formato a due byte anziché one formato byte

Vuol dire che avrei dovuto richiamare FindClass da C in questo modo: FindClass("java/lang/String\0")

cioè con doppia '\ 0' alla fine?

+2

Che cosa è successo quando hai provato, ha funzionato o no? – mah

+0

@mah Le domande richiedono "dovrebbe" non "potrebbe". È sulla correttezza tecnica non ["programmazione per coincidenza".] (Http://pragprog.com/the-pragmatic-programmer/extracts/coincidence) Naturalmente funziona ma non è corretto. –

risposta

3

Il set di caratteri, la codifica e la terminazione sono tre cose diverse. Ovviamente, una codifica è progettata per un set di caratteri specifico ma un set di caratteri può essere codificato in più modi. E, spesso, un terminatore (se usato) è un carattere codificato, ma con UTF-8 modificato, questo non è il caso.

Java utilizza il set di caratteri Unicode. Per i tipi stringa e char, utilizza la codifica UTF-16. Il tipo di stringa viene contato; Non usa un terminatore.

In C, le stringhe terminate sono comuni, nonché le codifiche a singolo byte di vari set di caratteri. I compilatori C e C++ terminano le stringhe letterali con il carattere NUL. Nella codifica del set di caratteri di destinazione del compilatore, questo è uno o due 0x00 byte. Quasi tutti i set di caratteri comuni e le loro codifiche hanno la stessa rappresentazione in byte per i caratteri ASCII senza controllo . Questo è vero per la codifica UTF-8 del set di caratteri Unicode. (Ma, nota che non è vero per i caratteri al di fuori del sottoinsieme limitato.)

I progettisti JNI hanno scelto di utilizzare questa "interoperabilità" limitata tra le stringhe C. Molte funzioni JNI accettano con terminazione 0x00 modificata stringhe UTF-8. Sono compatibili con ciò che un compilatore C produce da una stringa letterale nel codice sorgente, sempre a condizione che i caratteri siano limitati ai caratteri ASCII senza controllo. Questo copre il caso d'uso della scrittura del pacchetto Java & classe, metodo e stringhe di campo in JNI. (Bene, quasi: Java consente qualsiasi simbolo di valuta Unicode in un identificatore.)

Quindi, è possibile passare i valori letterali di stringa C alle funzioni JNI in uno stile WYSIWYG. Non c'è bisogno di aggiungere un terminatore, il compilatore lo fa. Il compilatore C codifica caratteri extra '\ 0' come 0x00 in modo da non causare alcun danno ma non è necessario.

Ci sono un paio di modifiche dalla codifica UTF-8 standard. Uno è quello di consentire alle funzioni C che prevedono un terminatore 0x00 di "gestire" le stringhe UTF-8 modificate, il carattere NUL (U + 00000) è codificato per evitare 0x00, che sarebbe lo standard. Ciò consente di modificare le stringhe UTF-8 modificate in un buffer con un terminatore 0x00 oltre i byte della stringa codificata originale. L'altra modifica è un po 'esoterica ma entrambe le modifiche rendono incompatibile una stringa UTF-8 modificata con una funzione UTF-8 strettamente conforme.

Non hai chiesto, ma c'è un altro uso di stringhe UTF-8 terminate 0x00 in JNI. È con le funzioni GetStringUTFChars e NewStringUTF. (La documentazione JNI in realtà non dice che GetStringUTFChars restituisce una stringa terminata 0x00 ma non sono note implementazioni JVM che non lo siano. Controlla la documentazione del tuo implementatore JVM o il codice sorgente.) Queste funzioni sono progettate sulla stessa base di "interoperabilità". Tuttavia, i casi d'uso sono diversi, rendendoli pericolosi. Sono generalmente utilizzati per passare stringhe Java tra funzioni C. Le funzioni C, in generale, non avrebbero idea di cosa sia UTF-8 modificato, o forse nemmeno di cosa siano UTF-8 o Unicode. È molto più diretto utilizzare le classi Java String e Charset per convertire in e da set di caratteri e codifiche per le quali sono state progettate le funzioni C. Spesso, si tratta di un'impostazione di sistema, di un'impostazione utente, di un'impostazione dell'applicazione o di un'impostazione di thread che determina quale funzione C sta utilizzando. La classe Java String tenta di conformarsi a tali impostazioni quando non viene fornita una codifica specifica per una conversione. Ma, in molti casi, la codifica desiderata è fissa e può essere specificata con intento chiaro.

3

No, according to the first reference I found, vuol dire che dovrebbe essere codificato in questo modo:

FindChar("java/lang/String\xc0\x80"); 
          ^
           | 
           | 
        This is not the shortest 
        way to encode the codepoint 
        U+0000, which is why it's 
        "modified" UTF-8. 

Si noti che questo presuppone che si sta veramente cercando nomi di classi i cui nomi finiscono in U + 0000, il che è piuttosto improbabile. La stringa C dovrebbe essere terminato proprio come normale, con un singolo 0 byte come si ottiene da solo:

FindChar("java/lang/String"); 

La particolare codifica a 2 byte di U + 0000 fornito da UTF-8 modificato conta solo se si desidera mettere U + 0000 in una stringa, ed essere ancora in grado di differenziarlo dal terminatore C.

3

No, non è codificare lo zero terminante, non fa parte del nome classe.