2010-03-27 4 views
14

Estoy trabajando en un programa C++ solo en inglés para Windows donde nos dijeron "siempre use std :: wstring", pero parece que nadie en el equipo realmente tiene mucho entendimiento más allá de eso.Confundido sobre std :: wstring, UTF-16, UTF-8 de C++ y mostrando cadenas en una GUI de Windows

Ya leí la pregunta con el título "std::wstring VS std::string. Fue muy útil, pero todavía no entiendo cómo aplicar toda esa información a mi problema.

El programa en el que estoy trabajando muestra datos en una GUI de Windows. Esa información se conserva como XML. A menudo transformamos ese XML usando XSLT en HTML o XSL: FO para propósitos de informes.

Mi sensación basada en lo que he leído es que el código HTML debe codificarse como UTF-8. Sé muy poco sobre el desarrollo de la GUI, pero lo poco que he leído indica que todo el material de la GUI se basa en cadenas codificadas en UTF-16.

Estoy tratando de entender dónde me deja. Digamos que decidimos que todos nuestros datos persistentes deberían ser XML codificados con UTF-8. ¿Esto significa que para mostrar datos persistentes en un componente de UI, realmente debería estar realizando algún tipo de proceso de transcodificación UTF-8 a UTF-16?

Sospecho que mi explicación podría usar una aclaración, por lo que intentaré proporcionarla si tiene alguna pregunta.

Respuesta

7

Windows a partir de NT4 se basa en cadenas codificadas en Unicode, sí. Las primeras versiones se basaban en UCS-2, que es el predecesor o UTF-16, y por lo tanto no es compatible con todos los caracteres que UTF-16 hace. Las versiones posteriores se basan en UTF-16. Sin embargo, no todos los sistemas operativos se basan en UTF-16/UCS-2. * los sistemas de nix, por ejemplo, se basan en UTF-8 en su lugar.

UTF-8 es una muy buena opción para almacenar datos persistentemente. Es una codificación universalmente compatible en todos los entornos Unicode, y es un buen equilibrio entre el tamaño de los datos y la compatibilidad de datos sin pérdida.

Sí, tendría que analizar el XML, extraer la información necesaria del mismo y decodificarlo y transformarlo en algo que la interfaz de usuario pueda usar.

+3

En realidad no es exacto decir que * nix se basa en UTF-8, la forma en que Windows se basa en UTF-16. Se basa en una codificación de caracteres definida localmente (en terminología de Windows, ANSI). POSIX requiere que ciertos caracteres (incluido NUL) se representen en un solo byte, por lo que UTF-16 y UTF-32 no están permitidos, pero UTF-8 sí lo está. – dan04

3

Una de las ventajas de usar std :: wstring en Windows para cadenas relacionadas con GUI, es que internamente todas las llamadas a la API de Windows usan y operan en UTF-16. Si alguna vez ha notado que hay 2 versiones de todas las llamadas a API de Win32 que toman argumentos de cadena. Por ejemplo, "MessageBoxA" y "MessageBoxW". Existen dos definiciones, y de hecho se puede llamar a cualquiera que desee, pero si se incluye con el soporte Unicode habilitado, entonces sucederá lo siguiente:

#define MessageBox MessageBoxW 

A continuación, entrar en TCHAR de y otros trucos de Microsoft para tratar de hacer es más fácil tratar con API que tienen una versión ANSI y Unicode. En resumen, puede llamar a cualquiera, pero bajo el capó del kernel de Windows en Unicode, por lo que pagará el costo de conversión a Unicode para cada cadena que acepte la llamada API de Win32 si no utiliza la versión de char ancha.

UTF-16 and Windows kernel use

4

std :: wstring es técnicamente UCS-2: Se utilizan dos bytes para cada carácter y las tablas de códigos mayoría mapa a formato Unicode. ¡Es importante entender que UCS-2 no es lo mismo que UTF-16! UTF-16 permite "pares suplentes" para representar caracteres que están fuera del rango de dos bytes, pero UCS-2 usa exactamente dos bytes para cada carácter, punto.

La mejor regla para su situación es hacer su transcodificación cuando se lee y escribe en el disco. Una vez que esté en la memoria, mantenlo en formato UCS-2. API de Windows leerá como si se tratara de UTF-16 (es decir, mientras que std :: wstring no entiende el concepto de pares suplentes, si crea manualmente (que no va, si su único idioma es Inglés), Windows los leerá).

Cada vez que usted está leyendo los datos dentro o fuera de los formatos de serialización (como XML) en los tiempos modernos, es probable que tengas que hacer transcodificación. Es una realidad desagradable y desafortunada, pero inevitable ya que Unicode es una codificación de caracteres de ancho variable y la mayoría de las operaciones basadas en caracteres en C++ se realizan como matrices, para lo cual se necesita un espaciado uniforme.

Los marcos de nivel superior, como .NET, oscurecen la mayoría de los detalles, pero detrás de escena, están manejando la transcodificación de la misma manera: cambiando datos de ancho variable a cadenas de ancho fijo, manipulándolos, y luego volver a cambiarlos a codificaciones de ancho variable cuando sea necesario para la salida.

+2

¿Qué dice que std :: wstring es UCS-2? std :: wstring simplemente usa wchar_t en lugar de och como base para la cadena. Y wchar_t depende de la implementación. Pero supongo que en la mayoría de los sistemas modernos de 32/64 bits será lo mismo que char16_t. En qué éter UCS-2 o UTF-16 cabrían ya que tienen 16 bits de ancho. – jpyllman

+2

Buen punto. std :: wstring no es técnicamente una codificación de caracteres de ningún tipo. Son solo caracteres de dos bytes de ancho. ¡Pero UTF-16 no tiene ** 16 bits de ancho! Utiliza un ** mínimo ** de 16 bits para almacenar un carácter, pero puede usar hasta 32 bits si el personaje lo requiere. Esto ha llevado a una cantidad de ataques de desbordamiento de búfer contra aplicaciones que miden cadenas codificadas en UTF-16 en caracteres y luego asignan (caracteres + 1) * 2 bytes de almacenamiento por error y copian ciegamente la cadena. –

+0

@Dan Story: Y puede ser incluso peor que eso si hay personajes combinados para tratar en un solo grafema. –

1

Incluso si usted dice que sólo tiene Inglés en sus datos, es probable que mal. Como ahora estamos en un mundo global, los nombres/direcciones/etc. tienen caracteres extranjeros. De acuerdo, no sé qué tipo de datos tienes, pero en general diría que compila tu aplicación para que sea compatible con UNICODE tanto para almacenar datos como para mostrarlos al usuario. Eso sugeriría usar XML con UTF-8 para almacenar y versiones UNICODE de llamadas de Windows cuando haga GUI. Y dado que la GUI de Windows usa UTF-16, donde cada token es de 16 bits, sugiero almacenar los datos en la aplicación en una cadena de 16 bits de ancho. Y supongo que su compilador para Windows tendría std :: wstring como de 16 bits solo para este propósito.

Así entonces usted tiene que hacer un montón de conversión entre UTF-16 y UTF-8. Hazlo con alguna biblioteca existente, como por ejemplo ICU.

+0

De maldición no hay nada de malo almacenando datos en XML con UTF-16. Pero sugeriría UTF-8 de todos modos para una portabilidad más fácil entre diferentes sistemas. – jpyllman

+2

UTF-8 es casi siempre una mejor opción para XML de todos modos, porque el predominio del inglés como lenguaje informático significa que la mayoría de todos los caracteres de marcado en la mayoría de los documentos XML van a caer dentro del rango de 8 bits de codificación UTF-8 , lo que resulta en ahorros significativos de espacio. En general, esto se aplica incluso si el idioma del documento * contenido * está en un idioma distinto del inglés que utiliza un juego de caracteres extendido. –

+2

Y en realidad podría ser incluso mejor usar std :: string en el programa y almacenar UTF-8 en ellos. Y luego solo conviértase en UTF-16 para Windows cuando desee mostrar algo. Solo trabajando con UTF-8 en cualquier otro sentido. – jpyllman

5

yo sepa cuando se trabaja con std :: wstring en Windows en C++ y tienda utilizando UTF-8 en los archivos (que suena bien y razonable), entonces usted tiene que convertir los datos a UTF-8 cuando se escribe en un archivo, y vuelva a convertir a UTF-16 cuando lea desde un archivo. Echa un vistazo a este enlace: Writing UTF-8 Files in C++.

me gustaría seguir con el valor por defecto de Visual Studio del proyecto -> Propiedades -> Configuración de Propiedades -> General -> Juego de caracteres -> Uso de caracteres Unicode Conjunto, utilice el tipo wchar_t (es decir, con std :: wstring) y no usa el tipo TCHAR. (Por ejemplo yo sólo tiene que utilizar la versión wcslen de strlen y no _tcslen.)

Cuestiones relacionadas