2010-11-12 8 views
11

Así que finalmente he vuelto a mi tarea principal, portar un proyecto C++ bastante grande desde Windows a la Mac.Cadenas multiplataforma (y Unicode) en C++

Directamente He sido golpeado por el problema donde wchar_t tiene 16 bits en Windows pero 32 bits en la Mac. Esto es un problema porque todas las cadenas están representadas por wchar_t y habrá datos de cadenas entre máquinas Windows y Mac (tanto en datos en disco como en formularios de datos de red). Debido a la forma en que funciona, no sería totalmente sencillo convertir las cadenas en algún formato común antes de enviar y recibir los datos.

También hemos comenzado a admitir muchos más idiomas recientemente, por lo que estamos comenzando a manejar una gran cantidad de datos Unicode (y también a idiomas de derecha a izquierda).

Ahora, podría estar combinando varias ideas aquí y causándome más problemas de los necesarios, razón por la cual hago esta pregunta. Estamos pensando que almacenar todos nuestros datos de cadenas en memoria como UTF-8 tiene mucho sentido. Resuelve el problema de que wchar_t es de diferentes tamaños, significa que podemos admitir fácilmente varios idiomas y también reduce drásticamente nuestra huella de memoria (tenemos MUCHAS cadenas en su mayoría inglesas cargadas) pero no parece que mucha gente lo esté haciendo esta. ¿Hay algo que nos falta? Existe el problema obvio de que debe lidiar cuando la longitud de la cadena puede ser menor que el tamaño de la memoria que almacena esa cadena de datos.

¿O está usando UTF-16 una mejor idea? ¿O deberíamos quedarnos con wchar_t y escribir el código para convertir entre wchar_t y, por ejemplo, Unicode en lugares donde leemos/escribimos en el disco o la red?

Me doy cuenta de que esto está peligrosamente cerca de pedir opiniones, pero estamos nerviosos porque estamos pasando por alto algo obvio, porque no parece que haya muchas clases de cadenas Unicode (por ejemplo), pero aún así hay muchas código para convertir a/desde Unicode como en boost :: locale, iconv, utf-cpp e ICU.

+0

Sólo una palabra que decir. http://utf8everywhere.org –

Respuesta

7

Utilice siempre un protocolo definido para el byte cuando se trate de un archivo o una conexión de red. No confíe en cómo un compilador C++ almacena algo en la memoria. Para el texto Unicode, esto significa elegir una codificación y un orden de bytes (está bien, a UTF-8 no le importa el orden de los bytes). Incluso si las plataformas que actualmente desea admitir tienen arquitecturas similares, probablemente llegue otra plataforma popular con un comportamiento diferente o incluso un nuevo sistema operativo para una de sus plataformas existentes, y le alegrará que haya escrito un código portátil.

1

Como regla general: UTF-16 para el procesamiento, UTF-8 para la comunicación & de almacenamiento.

Claro, cualquier regla se puede romper y esta no está tallada en piedra. Pero debes saber cuándo está bien romperlo.

Por ejemplo, podría ser una buena idea usar algo más si el entorno que está utilizando quiere algo más. Pero las API de Mac OS X usan UTF-16, al igual que Windows. Entonces UTF-16 tiene más sentido. Es más fácil convertir antes de poner/obtener cosas en la red (porque probablemente lo haga en 2-3 rutinas) que hacer todas las conversiones para llamar a las API de OS.

También importa el tipo de aplicación que desarrolle. Si se trata de algo con muy poco procesamiento de texto y muy pocas llamadas al sistema (algo así como un servidor de correo electrónico que principalmente mueve las cosas sin cambiarlas), entonces UTF-8 podría ser una buena opción.

Así que, por mucho que odie esta respuesta, "depende".

2

Tiendo a usar UTF-8 como la representación interna. Solo pierde la verificación de la longitud de la cadena, y de todos modos no es realmente útil. Para la conversión de la API de Windows, uso mis propias funciones de conversión de Win32 I devised here. Como Mac y Linux son (para la mayoría de parte estándar UTF-8-aware, no es necesario convertir nada allí). Los bonos gratis que obtienes:

  1. usan el simple antiguo std::string.
  2. byte-wise network/stream transport.
  3. Para la mayoría de los idiomas, buena memoria de espacio.
  4. Para mayor funcionalidad: utf8cpp
+3

UTF-8 ** no ** le permite usar "plain old' std :: string' ". Tal vez si todo lo que quiere hacer es almacenar la cadena que está bien, pero no puede modificar la cadena en ese formato sin escribir su propia basura de procesamiento UTF-8 si usa ese contenedor. (es decir, no puede usar funciones miembro como 'std :: string :: find' y esperar que funcionen correctamente con cadenas UTF-8) Demasiada gente piensa" Ah, usaré UTF-8 "y piensan que pueden simplemente continúe tratando todo como matrices de caracteres, lo cual es falso. –

+5

@Billy: eso es cierto para cualquier codificación multibyte. std :: string es un contenedor de caracteres, no de glifos, y está perfectamente bien mantener el texto codificado en UTF-8 en std :: string y procesarlo con algo como utf8cpp –

+2

@Nemanja: sí, está bien usar un std :: cadena para almacenamiento, pero técnicamente puede * almacenar * cualquier cosa en std :: string (siempre que pueda proporcionar una faceta dummy 'std :: char_traits'). Sin embargo, cuando diga "Puede usar plain std :: string", las personas asumirán que realmente pueden usar la clase para cualquier cosa que no sea el almacenamiento de datos. Si ** solo almacenamiento ** es lo que buscas, entonces probablemente deberías usar 'vector' en su lugar. –

0

UCI tiene una cadena de C++ clase, UnicodeString

+1

ICU es una buena biblioteca para este tipo de cosas. Desafortunadamente también es ** enorme ** (El tamaño de la ICU compilado es de unos 25 MB). Eso puede estar bien en algunos casos, pero (por supuesto) no está bien en otros. Algunas personas realmente no necesitan todas las características que proporciona. OTOH, cualquiera que implemente lo que hace normalmente lo hace mal (cosas como la intercalación son diferentes por localidad, y la ICU maneja eso correctamente) –

+0

Mucho de eso son datos para 500 configuraciones regionales y cientos de conversores, y todas las bibliotecas posibles. Es bastante fácil de personalizar desde el punto de vista del código y los datos, si no necesita todo. La biblioteca principal de icuuc, por ejemplo, es de aproximadamente 1,4 MB sin incluir datos. –

Cuestiones relacionadas