2009-07-04 42 views
11

Esta es una pregunta de ANSI C. tengo el siguiente código.wchar_t vs wint_t

#include <stdio.h> 
#include <locale.h> 
#include <wchar.h> 

    int main() 
    { 
    if (!setlocale(LC_CTYPE, "")) { 
     printf("Can't set the specified locale! " 
       "Check LANG, LC_CTYPE, LC_ALL.\n"); 
     return -1; 
    } 
    wint_t c; 
    while((c=getwc(stdin))!=WEOF) 
     { 
    printf("%lc",c); 
     } 
    return 0; 
    } 

Necesito soporte completo UTF-8, pero incluso en este nivel más simple, ¿puedo mejorar esto de alguna manera? ¿Por qué se usa wint_t, y no wchar, con los cambios apropiados?

Respuesta

3

UTF-8 es una posible codificación para Unicode. Define 1, 2, 3 o 4 bytes por carácter. Cuando lo lea a través del getwc(), obtendrá de uno a cuatro bytes y creará un solo carácter Unicode codepoint, que cabría dentro de un wchar (que puede tener 16 o incluso 32 bits de ancho, dependiendo de la plataforma).

Pero como valores Unicode mapa para todos los valores de 0x0000 a 0xFFFF, no hay valores de la izquierda para volver códigos de condición o de error en (Algunos han señalado que Unicode es mayor que 16 bits, lo cual es cierto;. En se utilizan esos casos surrogate pairs. Pero el punto aquí es que Unicode utiliza todos los valores disponibles dejando ninguno para EOF.)

varios códigos de error incluyen EOF (WEOF), que asigna a -1. Si tuviera que poner el valor devuelto de getwc() en un wchar, no habría forma de distinguirlo de un carácter Unicode 0xFFFF (que, por cierto, está reservado de todos modos, pero estoy divagando).

Así que la respuesta es utilizar un más amplio tipo, un wint_t (o int), que posee al menos 32 bits. Eso le da a los 16 bits más bajos el valor real, y cualquier cosa con un bit establecido fuera de ese rango significa que sucedió algo diferente a un personaje que regresó.

¿Por qué no siempre usamos wchar en vez de wint? La mayoría de las funciones relacionadas con cadenas usan wchar porque en la mayoría de las plataformas es ½ del tamaño de wint, por lo que las cadenas tienen una huella de memoria más pequeña.

+2

Un carácter UTF-8 puede tener 4 bytes de longitud, técnico, incluso puede tomar 5 o 6 bytes, pero tales composiciones no son caracteres utf8 válidos. – quinmars

+0

Bueno, cierto. Puede tener 4 bytes de longitud si ingresa a los caracteres de plan adicionales de 0x10000 y superiores, pero eso se convierte en sustitutos cuando se trata de UTF-16, y pensé que estaba fuera del alcance de la pregunta. Y aunque son posibles secuencias de 5 o 6 bytes, siempre se pueden expresar en menos de 5 bytes y solo se generan con serializadores de baja calidad. – lavinio

+2

Su respuesta es en su mayoría correcta, pero usted proporciona demasiados detalles (platofrm depenent). 'wchar_t' es _no_ siempre 16 bits, puedo pensar en al menos 2 combinaciones de OS/compilador donde es 32. –

15

wint_t es capaz de almacenar cualquier valor válido de wchar_t. Un wint_t también es capaz de asumir el resultado de evaluar la macro WEOF (tenga en cuenta que un wchar_t es demasiado estrecho para contener el resultado).

+1

Ok, gracias. Entonces, en resumen: ¿cuándo es mejor usar wchar_t? ¿Por qué no siempre usar wint_t? –

+10

'wint_t' es' wchar_t' que 'int' es' char'. No usamos matrices de 'int' para cadenas estrechas, aunque' getc() 'devuelve' int' para poder devolver 'EOF'. Del mismo modo, no usamos matrices de 'wint_t' para cadenas anchas, aunque' getwc() 'devuelve' wint_t' para poder devolver 'WEOF'. – musiphil

+2

@musiphil: su comentario merece ser una respuesta, es el único que habla sobre la diferencia * conceptual * entre ellos. – MestreLion

6

Como @musiphil tan bien poner en su comentario, que voy a tratar de ampliar aquí, hay una diferencia conceptual entre wint_t y wchar_t.

Sus diferentes tamaños son un aspecto técnico que se deriva del hecho de que cada uno tiene muy clara la semántica :

  • wchar_t es lo suficientemente grande como para almacenar caracteres , o puntos de código si lo prefiere. Como tales, son sin firma. Son análogos a char, que, en prácticamente todas las plataformas, se limitaba a 256 valores de 8 bits. Entonces, las variables de cadenas anchas son naturalmente matrices o punteros de este tipo.

  • Ahora introduzca cadena funciones, algunas de las cuales tienen que ser capaces de devolver cualquier wchar_t plus adicionales estados. Por lo que su tipo de devolución debe ser mayor que wchar_t. Entonces se usa wint_t, que puede expresar cualquier char ancho y también WEOF. Al ser un estado, también puede ser negativo (y generalmente lo es), por lo tanto, wint_t es probablemente con la firma. Digo "posiblemente" porque el estándar C no cumple mandato. Pero independientemente de la señal, los valores de estado deben ser fuera de el rango de wchar_t. Solo son útiles como valores de retorno, y nunca tuvieron la intención de almacenar tales caracteres.

La analogía con el "clásico" char y int es grande para despejar cualquier confusión: las cadenas no son de tipo int [], son char var[] (o char *var). Y no porque char es "la mitad del tamaño de int", sino porque eso es lo que una cadena es.

Tu código es correcto: c se utiliza para verificar el resultado de getwch(), por lo que es wint_t. Y si su valor no es WEOF, como prueba su if, entonces es seguro asignarlo a un carácter wchar_t (o una matriz de cadena, puntero, etc.)

+1

Hmmmm No estoy de acuerdo: La especificación C11 dice que 'wint_t' puede estar firmado o no. Además, dice "El valor de la macro' WEOF' puede diferir del de 'EOF' y no tiene por qué ser negativo." – chux

+2

@chux: hecho ... Espero que haya mejorado ahora, y gracias por la nota – MestreLion

+2

'wchar_t' no es necesariamente lo suficientemente grande como para almacenar puntos de código. En particular, en Windows es de solo 16 bits, lo que significa que se requiere el uso de pares de sustitución para representar puntos de código fuera del plano multilingüe básico. – rdb