2012-01-11 15 views
8

En C11, se ha agregado un nuevo literal de cadena con el prefijo u8. Esto devuelve una matriz de caracteres con el texto codificado para UTF-8. Como es esto posible? ¿No está firmado un char normal? ¿Quiere decir que tiene un poco menos de información para usar debido al bit de signo? Mi lógica mostraría que una cadena de texto UTF-8 necesitaría ser una matriz de caracteres sin signo.¿Cómo puede char [] representar una cadena UTF-8?

+0

UTF-8 representa caracteres que usan más de 8 bits (lo cual siempre me confunde ya que UTF-16 tiene 16 bits). Además, un char es solo un grupo de bits, por lo que tal vez se firme o no solo importa si está pensando en el valor como un número. Si está pensando en que es (parte de) una representación de un símbolo utf-8, no importa si el compilador cree que el área en la memoria representa un número firmado o no firmado. (Esta no es una respuesta, solo cómo mi lógica lo interpreta). – Oliver

+0

@Oliver ¿Cuál es la parte que lo confunde? UTFf-8 es tanto 8 bit como UTF-16 es 16 bit. –

+0

@MrLister Los caracteres UTF-16 ocupan 1 o 2 bytes de memoria. Los caracteres UTF-8 pueden ocupar cualquier número de byes de memoria (generalmente de 1 a 6 bytes). Entonces, en mi opinión, 'UTF-8' sería una codificación de 8 bits tipo ascii. Mientras que el verdadero UTF-8 sería mejor llamado UTF-48, o similar. O al menos, creo que así es como funciona. Nunca entendí las codificaciones de caracteres de ancho variable cuando estaba haciendo C hace un par de años, y ahora trabajo en idiomas más felices donde esto no es realmente una preocupación ... – Oliver

Respuesta

5

¿No es un chantaje normal firmado?

Es dependiente de la implementación si char es signed o unsigned.

Además, el bit de signo no se "pierde", todavía se puede usar para representar información, y char no es necesariamente de 8 bits (puede ser mayor en algunas plataformas).

+0

* "también puede estar sin firmar" * ... pero no al mismo tiempo :-) –

+0

El estándar dice 'char' siempre tiene 1 byte de longitud. Sin embargo, el tamaño de un byte puede variar. Use 'CHAR_BIT' (de' limits.h') para conocer el tamaño real de 1 byte. – jweyrich

1

No, un bit de signo es un poco no obstante! Y la especificación UTF-8 en sí misma no dice que los caracteres deben estar sin firmar.

PS Wat es kookwekker voor 'n naam?

6

Hay un problema potencial aquí:

Si una implementación con CHAR_BIT == 8 utiliza firmar grados de magnitud representación de char (por lo char se firma), entonces cuando UTF-8 requiere que el patrón de bits 10000000, que es una negativo 0. Entonces, si la implementación no admite 0 negativo, entonces una cadena UTF-8 dada podría contener un valor inválido (trap) de char, lo cual es problemático. Incluso si admite cero negativo, el hecho de que el patrón de bits 10000000 se compare igual que char con el patrón de bits 00000000 (el terminador nul) es probable que cause problemas al utilizar datos UTF-8 en un char[].

Creo que esto significa que para las implementaciones C11 de magnitud de señal, char debe estar sin firmar. Normalmente depende de la implementación si char está firmado o no, pero por supuesto si char está siendo firmado resulta en que no se implementan los literales UTF-8 correctamente, entonces el implementador solo tiene que seleccionar unsigned. Como un aparte, este ha sido el caso para las implementaciones de complemento de 2 de C++ todo el tiempo, ya que C++ permite char así como unsigned char para ser utilizado para acceder a representaciones de objetos. C solo permite unsigned char.

En complemento a 2 y el complemento 1s', los patrones de bits necesarios para UTF-8 datos son valores válidos de signed char, por lo que la aplicación es libre de hacer char ya sea con o sin signo y aún así ser capaz de representar cadenas UTF-8 en char[]. Esto se debe a que todos los patrones de 256 bits son valores de complemento de 2 válidos, y UTF-8 no usa el byte 11111111 (complemento negativo de 1s).

+0

Tu publicación utiliza una premisa equivocada, a saber, que las implementaciones serían lo suficientemente tontas como para permitir valores de -0 para los caracteres. Ellos nunca lo son. –

+2

@Mr Lister: No creo que mi respuesta haga ninguna suposición sobre qué implementaciones realmente hacen. Simplemente enumera lo que están (no) autorizados a hacer, y en particular la única representación recientemente descartada por el requisito en C11 para soportar UTF-8. Para todos los propósitos prácticos, cada implementación es un complemento de 2, pero el estándar continúa permitiendo las alternativas (tontas). –

+0

Creo que su publicación es muy perspicaz, pero aquí es donde estoy confundido: el estándar C++ 11 permite que un 'unsigned char' y' char' se usen para aliasing (vea §3.10/15) y C11 incluso permite * all * tipos de caracteres (ver §6.5/7). Para mí, esto significa que estos tipos deben ser capaces de leer un byte de valor '11111111' (o * cualquier * otro valor de byte). En C++ 11, esto puede resolverse haciendo que un simple 'char' sin signo * si el complemento * 2 no se utiliza. Pero en C11 esto no puede resolverse nunca si el complemento 2 * no es * utilizado, porque el aliasing debe funcionar con todos los tipos de caracteres (§6.5/7), es decir, incluso explícitamente ... – JohnCand

1

La firma de char no importa; utf8 se puede manejar con solo operaciones de desplazamiento y máscara (que pueden ser engorrosas para tipos con signo, pero no imposible) Pero: utf8 necesita al menos 8 bits, por lo que "assert (CHAR_BIT> = 8);"

Para ilustrar por punto: los siguientes fragmentos no contienen operaciones aritméticas en el valor del carácter, solo cambian la máscara &.

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

Tenga en cuenta que la norma _guarantees_ 'CHAR_BIT' ≥ 8. –

Cuestiones relacionadas