È UTF-16 a larghezza fissa o variabile? Perché UTF-8 non ha un problema di ordine dei byte?

15
  1. È UTF-16 a larghezza fissa o variabile? Ho avuto risultati diversi da diverse fonti:

    Da link :

    UTF-16 stores Unicode characters in sixteen-bit chunks.

    Da link :

    UTF-16 (16-bit Unicode Transformation Format) is a character encoding for Unicode capable of encoding 1,112,064[1] numbers (called code points) in the Unicode code space from 0 to 0x10FFFF. It produces a variable-length result of either one or two 16-bit code units per code point.

  2. Dalla prima fonte

    UTF-8 also has the advantage that the unit of encoding is the byte, so there are no byte-ordering issues.

    Perché UTF-8 non ha un problema di ordine dei byte? È a larghezza variabile e un personaggio può contenere più di un byte, quindi penso che l'ordine dei byte può ancora essere un problema?

Grazie e saluti!

    
posta Tim 23.07.2011 - 01:45
fonte

2 risposte

12

(1) What does byte sequence mean, an arrary of char in C? Is UTF-16 a byte sequence, or what is it then? (2) Why does a byte sequence have nothing to do with variable length?

Sembra che tu stia fraintendendo i problemi di endian. Ecco un breve riassunto.

Un numero intero a 32 bit occupa 4 byte. Ora conosciamo l'ordine logico di questi byte. Se hai un intero a 32 bit, puoi ottenere il byte più alto con il seguente codice:

uint32_t value = 0x8100FF32;
uint8_t highByte = (uint8_t)((value >> 24) & 0xFF); //Now contains 0x81

Va tutto bene. Il punto in cui inizia il problema è il modo in cui vari hardware memorizzano e recuperano gli interi dalla memoria.

Nell'ordine Big Endian, una parte di memoria di 4 byte che leggerai come numero intero a 32 bit verrà letta con il primo byte come byte alto:

[0][1][2][3]

Nell'ordine Little Endian, un pezzo di memoria di 4 byte che tu leggi come un intero a 32 bit verrà letto con il primo byte che è il basso byte:

[3][2][1][0]

Se hai un puntatore a un puntatore a un valore a 32 bit, puoi fare ciò:

uint32_t value = 0x8100FF32;
uint32_t *pValue = &value;
uint8_t *pHighByte = (uint8_t*)pValue;
uint8_t highByte = pHighByte[0]; //Now contains... ?

Secondo C / C ++, il risultato di questo non è definito. Potrebbe essere 0x81. O potrebbe essere 0x32. Tecnicamente, potrebbe restituire qualsiasi cosa, ma per i sistemi reali, restituirà uno o l'altro.

Se si dispone di un puntatore a un indirizzo di memoria, è possibile leggere quell'indirizzo come valore a 32 bit, a 16 bit o a 8 bit. Su una macchina big endian, il puntatore punta al byte alto; su una piccola macchina endian, il puntatore punta al byte basso.

Si noti che si tratta di leggere e scrivere su / dalla memoria. Ha niente da fare con il codice C / C ++ interno. La prima versione del codice, quella che C / C ++ non dichiara come indefinita, lavorerà always per ottenere il byte più alto.

Il problema si verifica quando inizi a leggere i flussi di byte. Ad esempio da un file.

I valori a 16 bit hanno gli stessi problemi di quelli a 32 bit; hanno solo 2 byte invece di 4. Pertanto, un file può contenere valori a 16 bit memorizzati in big endian o little endian.

UTF-16 è definito come una sequenza di valori a 16 bit . In effetti, è un uint16_t[] . Ogni singola unità di codice è un valore a 16 bit. Pertanto, per caricare correttamente UTF-16, è necessario sapere qual è la endianità dei dati.

UTF-8 è definito come una sequenza di valori a 8 bit . È un uint8_t[] . Ogni singola unità di codice ha una dimensione di 8 bit: un singolo byte.

Ora, sia UTF-16 che UTF-8 consentono più unità di codice (valori a 16 bit o 8 bit) da combinare insieme per formare un punto di codice Unicode (un "carattere", ma questo è non il termine corretto, è una semplificazione). L' ordine di queste unità di codice che formano un punto di codice è dettato dalle codifiche UTF-16 e UTF-8.

Durante l'elaborazione di UTF-16, si legge un valore a 16 bit, facendo qualsiasi conversione endian è necessaria. Quindi, si rileva se si tratta di una coppia surrogata; se lo è, allora leggi un altro valore a 16 bit, combina i due e, da quello, ottieni il valore di codice Unicode.

Durante l'elaborazione di UTF-8, si legge un valore a 8 bit. Non è possibile alcuna conversione endian, poiché esiste un solo byte. Se il primo byte indica una sequenza multi-byte, allora si legge un certo numero di byte, come dettato dalla sequenza multi-byte. Ogni singolo byte è un byte e quindi non ha alcuna conversione endian. L'ordine di questi byte nella sequenza, proprio come l'ordine delle coppie surrogate in UTF-16, è definito da UTF-8.

Quindi non ci possono essere problemi con Endian UTF-8.

    
risposta data 24.07.2011 - 02:00
fonte
10

La risposta di Jeremy Banks è corretta fino alla fine, ma non ha risolto l'ordine dei byte.

Quando usi UTF-16, la maggior parte degli glifi viene memorizzata usando una parola di due byte, ma quando la parola viene memorizzata in un file su disco, quale ordine usi per memorizzare i byte costitutivi?

Ad esempio, il glifo CJK (cinese) per la parola "acqua" ha una codifica UTF-16 in esadecimale di 6C34. Quando lo scrivi come due byte su disco, lo scrivi come "big-endian" (i due byte sono 6C 34)? O lo scrivi come "little-endian" (i due byte sono 34 6C)?

Con UTF-16, entrambi gli ordini sono legittimi e di solito indichi quale ha il file, facendo della prima parola nel file un Byte Order Mark (BOM), che per la codifica big-endian è FE FF, e per la codifica little-endian è FF FE.

UTF-32 ha lo stesso problema e la stessa soluzione.

UTF-8 non ha questo problema, perché è di lunghezza variabile e si scrive efficacemente la sequenza di byte di un glifo come se fosse little-endian. Ad esempio, la lettera "P" è sempre codificata usando un byte - 80 - e il carattere di sostituzione è sempre codificato utilizzando i due byte FF FD in quell'ordine.

Alcuni programmi inseriscono un indicatore a tre byte (EF BB BF) all'inizio di un file UTF-8 e questo aiuta a distinguere UTF-8 da codifiche simili come ASCII, ma non è molto comune tranne su MS Windows.

    
risposta data 23.07.2011 - 02:29
fonte

Leggi altre domande sui tag