¿Qué es wchar_t?
wchar_t se define de modo que la codificación char de cualquier configuración regional se pueda convertir en una representación wchar_t donde cada wchar_t representa exactamente un punto de código:
El tipo wchar_t es un tipo diferenciado cuyos valores pueden representar códigos distintos para todos los miembros del conjunto de caracteres extendido más grande especificado entre las configuraciones regionales admitidas (22.3.1).
- C ++ [básico.fundamental] 3.9.1 / 5
Esto no requiere que wchar_t sea lo suficientemente grande para representar cualquier carácter de todas las configuraciones regionales simultáneamente. Es decir, la codificación utilizada para wchar_t puede diferir entre las configuraciones regionales. Lo que significa que no es necesario convertir una cadena en wchar_t usando una configuración regional y luego volver a convertir a char usando otra configuración regional. 1
Dado que usar wchar_t como una representación común entre todas las configuraciones regionales parece ser el uso principal de wchar_t en la práctica, es posible que se pregunte para qué sirve si no es para eso.
La intención y el propósito originales de wchar_t era simplificar el procesamiento de texto definiéndolo de modo que requiera una asignación uno a uno de las unidades de código de una cadena a los caracteres del texto, lo que permite el uso de los mismos algoritmos simples que se utilizan con cadenas ascii para trabajar con otros lenguajes.
Desafortunadamente, la redacción de la especificación de wchar_t asume un mapeo uno a uno entre caracteres y puntos de código para lograr esto. Unicode rompe esa suposición 2 , por lo que tampoco puede usar wchar_t de manera segura para algoritmos de texto simples.
Esto significa que el software portátil no puede usar wchar_t como una representación común de texto entre configuraciones regionales o para permitir el uso de algoritmos de texto simples.
¿De qué sirve wchar_t hoy?
No mucho, para el código portátil de todos modos. Si __STDC_ISO_10646__
se define, los valores de wchar_t representan directamente los puntos de código Unicode con los mismos valores en todas las configuraciones regionales. Eso hace que sea seguro realizar las conversiones entre ubicaciones mencionadas anteriormente. Sin embargo, no puede confiar solo en él para decidir que puede usar wchar_t de esta manera porque, aunque la mayoría de las plataformas Unix lo definen, Windows no lo hace, aunque Windows usa la misma configuración regional wchar_t en todas las configuraciones regionales.
La razón por la que Windows no define __STDC_ISO_10646__
es porque Windows usa UTF-16 como su codificación wchar_t, y porque UTF-16 usa pares sustitutos para representar puntos de código mayores que U + FFFF, lo que significa que UTF-16 no satisface los requisitos de __STDC_ISO_10646__
.
Para el código específico de la plataforma, wchar_t puede ser más útil. Esencialmente se requiere en Windows (por ejemplo, algunos archivos simplemente no se pueden abrir sin usar los nombres de archivo wchar_t), aunque Windows es la única plataforma donde esto es cierto hasta donde yo sé (así que tal vez podamos pensar en wchar_t como 'Windows_char_t').
En retrospectiva, wchar_t claramente no es útil para simplificar el manejo de texto o como almacenamiento de texto independiente de la configuración regional. El código portátil no debe intentar utilizarlo para estos fines. El código no portátil puede resultar útil simplemente porque alguna API lo requiere.
Alternativas
La alternativa que me gusta es usar cadenas C codificadas en UTF-8, incluso en plataformas que no son particularmente amigables con UTF-8.
De esta manera, uno puede escribir código portátil usando una representación de texto común en todas las plataformas, usar tipos de datos estándar para su propósito previsto, obtener el soporte del lenguaje para esos tipos (por ejemplo, cadenas literales, aunque algunos trucos son necesarios para que funcione para algunos compiladores), algunos soporte de biblioteca estándar, soporte de depurador (pueden ser necesarios más trucos), etc. Con caracteres anchos, generalmente es más difícil o imposible obtener todo esto, y puede obtener diferentes piezas en diferentes plataformas.
Una cosa que UTF-8 no proporciona es la capacidad de usar algoritmos de texto simples como los que son posibles con ASCII. En este UTF-8 no es peor que cualquier otra codificación Unicode. De hecho, se puede considerar que es mejor porque las representaciones de unidades de código múltiple en UTF-8 son más comunes y, por lo tanto, es más probable que se noten y corrijan los errores en el manejo del código, tales representaciones de caracteres de ancho variable que si intenta ceñirse a UTF -32 con NFC o NFKC.
Muchas plataformas usan UTF-8 como su codificación nativa de caracteres y muchos programas no requieren ningún procesamiento de texto significativo, por lo que escribir un programa internacionalizado en esas plataformas es un poco diferente de escribir código sin considerar la internacionalización. Escribir código más ampliamente portátil o escribir en otras plataformas requiere insertar conversiones en los límites de las API que usan otras codificaciones.
Otra alternativa utilizada por algunos software es elegir una representación multiplataforma, como arreglos cortos sin firmar que contienen datos UTF-16, y luego proporcionar todo el soporte de la biblioteca y simplemente vivir con los costos de soporte de idiomas, etc.
C ++ 11 agrega nuevos tipos de caracteres anchos como alternativas a wchar_t, char16_t y char32_t con funciones de idioma / biblioteca asociadas. En realidad, no se garantiza que sean UTF-16 y UTF-32, pero no creo que ninguna implementación importante utilice otra cosa. C ++ 11 también mejora la compatibilidad con UTF-8, por ejemplo, con literales de cadena UTF-8, por lo que no será necesario engañar a VC ++ para que produzca cadenas codificadas en UTF-8 (aunque puedo continuar haciéndolo en lugar de usar el u8
prefijo) .
Alternativas a evitar
TCHAR: TCHAR es para migrar programas antiguos de Windows que asumen codificaciones heredadas de char a wchar_t, y es mejor olvidarlo a menos que su programa haya sido escrito en un milenio anterior. No es portátil y es inherentemente inespecífico acerca de su codificación e incluso su tipo de datos, lo que lo hace inutilizable con cualquier API que no sea TCHAR. Dado que su propósito es la migración a wchar_t, que hemos visto anteriormente no es una buena idea, no tiene ningún valor usar TCHAR.
1. No es necesario que los caracteres que se pueden representar en cadenas wchar_t pero que no se admiten en ninguna configuración regional se representen con un solo valor wchar_t. Esto significa que wchar_t podría usar una codificación de ancho variable para ciertos caracteres, otra clara violación de la intención de wchar_t. Aunque se puede argumentar que un carácter representable por wchar_t es suficiente para decir que la configuración regional 'admite' ese carácter, en cuyo caso las codificaciones de ancho variable no son legales y el uso de UTF-16 de Windows no es conforme.
2. Unicode permite representar muchos caracteres con múltiples puntos de código, lo que crea los mismos problemas para los algoritmos de texto simples que las codificaciones de ancho variable. Incluso si uno mantiene estrictamente una normalización compuesta, algunos caracteres aún requieren múltiples puntos de código. Ver: http://www.unicode.org/standard/where/