2010-07-21 10 views
52

Estoy leyendo sobre el conjunto de charater y las codificaciones en Windows. Noté que hay dos indicadores de compilación en el compilador de Visual Studio (para C++) llamados MBCS y UNICODE. Cuál es la diferencia entre ellos ? Lo que no entiendo es cómo UTF-8 es conceptualmente diferente de una codificación MBCS. Además, he encontrado la siguiente cita en MSDN:Diferencia entre MBCS y UTF-8 en Windows

Unicode es una codificación de caracteres de 16 bits

Esto niega lo que leí sobre el Unicode. Pensé que Unicode puede codificarse con diferentes codificaciones, como UTF-8 y UTF-16. ¿Alguien puede arrojar más luz sobre esta confusión?

Respuesta

92

me di cuenta de que hay dos opciones del compilador en compilador de Visual Studio (por C++) llamados MBCS y Unicode. ¿Cuál es la diferencia entre ellos?

Muchas funciones de la API de Windows vienen en dos versiones: una que lleva char parámetros (en una página de códigos específica para la localización) y uno que lleva wchar_t parámetros (en UTF-16).

int MessageBoxA(HWND hWnd, const char* lpText, const char* lpCaption, unsigned int uType); 
int MessageBoxW(HWND hWnd, const wchar_t* lpText, const wchar_t* lpCaption, unsigned int uType); 

Cada uno de estos pares de función también tiene una macro sin el sufijo, que depende de si se define la macro UNICODE.

#ifdef UNICODE 
    #define MessageBox MessageBoxW 
#else 
    #define MessageBox MessageBoxA 
#endif 

Con el fin de hacer este trabajo, el tipo TCHAR se define a abstraer el tipo de caracteres que utiliza las funciones de la API.

#ifdef UNICODE 
    typedef wchar_t TCHAR; 
#else 
    typedef char TCHAR; 
#endif 

Esto, sin embargo, was a bad idea. Siempre debe especificar explícitamente el tipo de carácter.

Lo que no estoy recibiendo es como UTF-8 es conceptualmente diferente de una codificación MBCS ?

MBCS significa "juego de caracteres multibyte". Para los de mente literal, parece que UTF-8 calificaría.

Pero en Windows, "MBCS" solo se refiere a las codificaciones de caracteres que se pueden usar con las versiones "A" de las funciones de la API de Windows. Esto incluye las páginas de códigos 932 (Shift_JIS), 936 (GBK), 949 (KS_C_5601-1987) y 950 (Big5), pero NOT UTF-8.

Para usar UTF-8, debe convertir la cadena a UTF-16 usando MultiByteToWideChar, llamar a la versión "W" de la función y llamar al WideCharToMultiByte en la salida. Esto es esencialmente lo que hacen las funciones "A", lo que me hace preguntarme why Windows doesn't just support UTF-8.

Esta incapacidad para admitir the most common character encoding hace que la versión "A" de la API de Windows sea inútil. Por lo tanto, debe utilizar siempre las funciones "W".

Unicode es una codificación de caracteres de 16 bits

Esto niega lo que leí sobre el Unicode.

MSDN está equivocado. Unicode es un conjunto de caracteres codificados de 21 bits que tiene varias codificaciones, siendo las más comunes UTF-8, UTF-16 y UTF-32. (También hay otras codificaciones Unicode, como GB18030, UTF-7 y UTF-EBCDIC.)

Siempre que Microsoft se refiera a "Unicode", realmente quieren decir UTF-16 (o UCS-2). Esto es por razones históricas. Windows NT fue uno de los primeros en adoptar Unicode, cuando se creía que 16 bits eran suficientes para todos, y UTF-8 solo se usaba en el Plan 9. Por lo tanto, UCS-2 era Unicode.

+0

Gracias por la información muy útil. – Naveen

+8

"Esto es para histórico" Me pregunto por qué no han reparado su documentación en los últimos> 15 años. – ybungalobill

+18

Ellos son Microsoft. La historia es falsa La resistencia es inútil. – tripleee

10

MBCS significa Multi-Byte Character Set y describe cualquier conjunto de caracteres donde un carácter está codificado en (posiblemente) más de 1 byte.

Los ANSI/ASCII juego de caracteres no son multi-byte.

UTF-8, sin embargo, es una codificación de varios bytes. Codifica cualquier carácter Unicode como una secuencia de 1, 2, 3 o 4 octetos (bytes).

Sin embargo, UTF-8 es solo una de varias posibles codificaciones concretas del juego de caracteres Unicode. En particular, UTF-16 es otra, y pasa a ser la codificación utilizada por Windows/.NET (IIRC). Aquí está la diferencia entre UTF-8 y UTF-16:

  • UTF-8 codifica cualquier carácter Unicode como una secuencia de 1, 2, 3, o 4 bytes.

  • UTF-16 codifica la mayoría de los caracteres Unicode como 2 bytes, y algunos como 4 bytes.

Es por lo tanto no correcto que Unicode es una codificación de caracteres de 16 bits. Es más bien algo así como una codificación de 21 bits (o incluso más en estos días), ya que abarca un conjunto de caracteres con los puntos de código U+000000 hasta U+10FFFF.

+1

Claro, pero en la documentación de la API de Windows usan Unicode para significar UTF-16. (Sospecho que la compatibilidad es limitada y es más seguro asumir que UCS-2.) Sí, el estándar Unicode va más allá de 21 bits. – Rup

+2

Esa pieza de documentación podría hacer que parezca que Unicode fuera UTF-16, sin embargo, eso no sería correcto (si es que es al revés). UTF-16 es solo una _codificación_ de Unicode. Y sí, de hecho, podrían significar UCS-2, no UTF-16. No estoy completamente seguro de eso. – stakx

+3

Windows NT solo es compatible con UCS-2. Windows ha sido compatible con UTF-16 completo desde Windows 2000, IIRC. –

13

_MBCS y _UNICODE son macros para determinar qué versión de rutinas TCHAR.H llamar. Por ejemplo, si utiliza _tcsclen para contar la longitud de una cadena, el preprocesador asignaría _tcsclen a una versión diferente según las dos macros: _MBCS y _UNICODE.

_UNICODE & _MBCS Not Defined: strlen 
_MBCS Defined: _mbslen 
_UNICODE Defined: wcslen 

Para explicar la diferencia de estas funciones de conteo de longitud de cuerda, considere el siguiente ejemplo.
Si tiene un cuadro de equipo que ejecuta la edición de Windows Simplified Chinese que usa GBK (página de códigos 936), compila un archivo fuente codificado en archivo gbk y lo ejecuta.

printf("%d\n", _mbslen((const unsigned char*)"I爱你M")); 
printf("%d\n", strlen("I爱你M")); 
printf("%d\n", wcslen((const wchar_t*)"I爱你M")); 

El resultado sería 4 6 3.

Aquí está la representación hexadecimal de I爱你M en GBK.

GBK:    49 B0 AE C4 E3 4D 00     

_mbslen sabe esta cadena está codificada en GBK, por lo que podría intepreter la cadena correctamente y obtener el resultado correcto 4 palabras: 49 como I, B0 AE como , C4 E3 como , 4D como M.

strlen solo conoce 0x00, por lo que obtiene 6.

wcslen consideran esta matriz hexdeciaml está codificada en UTF16LE, y se cuentan dos bytes como una sola palabra, por lo que obtener 3 palabras: 49 B0, AE C4, E3 4D.

como @xiaokaoy señaló, el único terminador válido para wcslen es 00 00. Por lo tanto, no se garantiza que el resultado sea 3 si el siguiente byte no es 00.

+1

Excelente. Pero en mi humilde opinión, el valor de retorno de ** wcslen ((const wchar_t *) "I 爱" M ") ** no se garantiza que sea 3. Si ** 49 B0 AE C4 E3 4D 00 ** no se sigue por un byte 00, ** wcslen ** devolverá un valor mayor que 3. – xiaokaoy

+0

Quiero decir, solo ** 00 00 ** se considera que es un carácter ancho nulo. – xiaokaoy

+2

No. ** L "I 爱 你 M" ** se garantiza que terminará con ** 4D 00 00 00 **. Pero ** (const wchar_t *) "I 爱 你 M" ** no lo es. – xiaokaoy

4

Como nota al pie de las otras respuestas, MSDN tiene un documento Generic-Text Mappings in TCHAR.H con tablas prácticas que resumen cómo las directivas de preprocesador _UNICODE y _MBCS cambian la definición de diferentes tipos de C/C++.

En cuanto a la frase "Unicode" y "Conjunto de caracteres de múltiples bytes", las personas ya han descrito cuáles son los efectos. Solo quiero enfatizar que ambos son palabras de Microsoft para algunas cosas muy específicas. (Es decir, se refieren a algo menos general y más particular a Windows de lo que uno esperaría si proviene de una comprensión no específica de Microsoft de la internacionalización de texto). Esas frases exactas aparecen y tienden a tener sus propias secciones/subsecciones de documentos técnicos de Microsoft, por ejemplo en Text and Strings in Visual C++

Cuestiones relacionadas