2012-01-11 8 views
8

In C11, una nuova stringa letterale è stata aggiunta con il prefisso u8. Questo restituisce una serie di caratteri con il testo codificato in UTF-8. Com'è possibile? Non è stato firmato un carattere normale? Significa che ha un po 'meno di informazioni da usare a causa del segno-bit? La mia logica spiegherebbe che una stringa di testo UTF-8 dovrebbe essere una matrice di caratteri non firmati.In che modo char [] rappresenta una stringa UTF-8?

+0

UTF-8 rappresenta caratteri che utilizzano più di 8 bit (che mi confonde sempre come UTF-16 è 16 bit). Inoltre, un char è solo un gruppo di bit, quindi forse essere firmato o non conta solo se stai pensando al valore come a un numero. Se si pensa che sia (parte di) una rappresentazione di un simbolo utf-8, indipendentemente dal fatto che il compilatore ritenga che l'area in memoria rappresenti un numero con segno o senza segno non ha importanza. (Questa non è una risposta, proprio come la mia logica interpreta questo.) – Oliver

+0

@Oliver Qual è la parte che ti confonde? UTFf-8 è tanto 8 bit quanto UTF-16 è 16 bit. –

+0

@MrLister I caratteri UTF-16 occupano 1 o 2 byte di memoria. I caratteri UTF-8 possono occupare un numero qualsiasi di byte di memoria (in genere da 1 a 6 byte). Quindi, a mio parere, 'UTF-8' sarebbe una codifica ascii-like a 8 bit. Mentre il vero UTF-8 sarebbe meglio denominato UTF-48, o simile. O almeno, penso che sia così che funziona. Non ho mai veramente capito le codifiche dei caratteri a larghezza variabile quando stavo facendo C un paio di anni fa, e ora lavoro in lingue più felici dove questo non è davvero un problema ... – Oliver

risposta

5

Non è un normale carattere firmato?

E 'implementazione-dipendente se char è signed o unsigned.

Inoltre, il bit di segno non è "perso", può ancora essere utilizzato per rappresentare informazioni e char non è necessariamente 8 bit di grandi dimensioni (potrebbe essere più grande su alcune piattaforme).

+0

* "potrebbe anche essere non firmato" * ... ma non allo stesso tempo :-) –

+0

Lo standard dice che 'char' è sempre lungo 1 byte. Tuttavia, la dimensione di un byte può variare. Usa 'CHAR_BIT' (da' limits.h') per conoscere la dimensione effettiva di 1 byte. – jweyrich

1

No, un po 'di segno è un po' comunque! E la stessa specifica UTF-8 non dice che i caratteri devono essere senza segno.

PS Wat è kookwekker voor 'naam?

6

C'è un potenziale problema qui:

Se un'implementazione con CHAR_BIT == 8 utilizza segno di magnitudo rappresentazione per char (così char è firmato), poi quando UTF-8 richiede il bit-pattern 10000000, che è un 0 negativo. Quindi se l'implementazione non supporta lo 0 negativo, quindi una determinata stringa UTF-8 potrebbe contenere un valore non valido (trap) di char, che è problematico. Anche se supporta lo zero negativo, il fatto che il modello di bit 10000000 sia uguale a un modello di bit 00000000 (il terminatore nul) è suscettibile di causare problemi quando si utilizzano dati UTF-8 in un char[].

Penso che questo significhi che per le implementazioni C11 di dimensioni-segno, char deve essere senza segno. Normalmente dipende dall'implementazione se char è firmato o non firmato, ma ovviamente se char è stato firmato significa che non è stato possibile implementare correttamente i valori letterali UTF-8, quindi l'implementatore deve semplicemente selezionare unsigned. Per inciso, questo è stato il caso per le implementazioni complementari di non-2 del C++ da sempre, poiché il C++ consente di utilizzare char e unsigned char per accedere a rappresentazioni di oggetti. C consente solo unsigned char.

In complemento a 2 e complemento 1s', i modelli di bit necessari per UTF-8 dati sono valori validi di signed char, quindi l'implementazione è libero di fare char sia con o senza segno e di essere ancora in grado di rappresentare stringhe UTF-8 in char[]. Questo perché tutti i modelli a 256 bit sono validi per i valori del complemento a 2 e UTF-8 non utilizza il byte 11111111 (zero negativo del complemento 1).

+0

Il tuo post utilizza una premessa sbagliata, ovvero che le implementazioni sarebbero abbastanza sciocche da consentire valori -0 per i caratteri. Non lo sono mai. –

+2

@ Mr Lister: Non penso che la mia risposta faccia alcuna supposizione su cosa effettivamente le implementazioni facciano. Si limita a enumerare ciò che è (non) autorizzato a fare, e in particolare l'unica rappresentazione esclusa dal requisito in C11 per supportare UTF-8. Per tutti gli scopi pratici, ogni implementazione è il complemento a 2, ma lo standard continua a consentire le (sciocche) alternative. –

+0

Penso che il tuo post sia molto perspicace, ma qui sono dove sono confuso: lo standard C++ 11 consente un 'char unsigned' e un' char' per l'aliasing (vedi §3.10/15) e C11 consente anche * all * tipi di caratteri (vedere §6.5/7). Per me, questo significa che questi tipi devono essere in grado di leggere un byte di valore '11111111' (o * qualsiasi * altro valore di byte). In C++ 11, questo può essere risolto facendo un semplice 'char' unsigned * se il complemento * 2 non viene usato. Ma in C11 questo non può mai essere risolto se il complemento a 2 * non è * usato, perché l'aliasing deve funzionare con tutti i tipi di caratteri (§6.5/7), cioè, anche esplicitamente ... – JohnCand

1

La firma di char non ha importanza; utf8 può essere gestito con solo operazioni di spostamento e maschera (che possono essere ingombranti per i tipi firmati, ma non impossibile) Ma: utf8 ha bisogno di almeno 8 bit, quindi "assert (CHAR_BIT> = 8);"

Per illustrare per punto: i seguenti frammenti non contengono operazioni aritmetiche sul valore del carattere, solo shift & maschera.

static int eat_utf8(unsigned char *str, unsigned len, unsigned *target) 
{ 
unsigned val = 0; 
unsigned todo; 

if (!len) return 0; 

val = str[0]; 
if ((val & 0x80) == 0x00) { if (target) *target = val; return 1; } 
else if ((val & 0xe0) == 0xc0) { val &= 0x1f; todo = 1; } 
else if ((val & 0xf0) == 0xe0) { val &= 0x0f; todo = 2; } 
else if ((val & 0xf8) == 0xf0) { val &= 0x07; todo = 3; } 
else if ((val & 0xfc) == 0xf8) { val &= 0x03; todo = 4; } 
else if ((val & 0xfe) == 0xfc) { val &= 0x01; todo = 5; } 
else { /* Default (Not in the spec) */ 
     if (target) *target = val; 
     return -1; } 


len--;str++; 
if (todo > len) { return -todo; } 

for(len=todo;todo--;) { 
     /* For validity checking we should also 
     ** test if ((*str & 0xc0) == 0x80) here */ 
     val <<= 6; 
     val |= *str++ & 0x3f; 
     } 

if (target) *target = val; 
return 1+ len; 
} 
+1

Si noti che Standard _garanzia_ 'CHAR_BIT' ≥ 8. –