web-dev-qa-db-fra.com

Différence entre MBCS et UTF-8 sous Windows

Je lis sur le jeu de caractères et les encodages sur Windows. J'ai remarqué qu'il y a deux indicateurs de compilateur dans le compilateur Visual Studio (pour C++) appelés MBCS et UNICODE. Quelle est la différence entre eux ? Ce que je ne comprends pas, c'est comment UTF-8 est conceptuellement différent d'un encodage MBCS? En outre, j'ai trouvé la citation suivante dans MSDN :

Unicode est un codage de caractères 16 bits

Cela annule tout ce que j'ai lu sur l'Unicode. Je pensais que l'unicode peut être encodé avec différents encodages tels que UTF-8 et UTF-16. Quelqu'un peut-il faire la lumière sur cette confusion?

57
Naveen

J'ai remarqué qu'il y a deux indicateurs de compilateur dans le compilateur Visual Studio (pour C++) appelés MBCS et UNICODE. Quelle est la différence entre eux ?

De nombreuses fonctions de l'API Windows sont disponibles en deux versions: une qui prend les paramètres char (dans une page de code spécifique aux paramètres régionaux) et une qui prend wchar_t paramètres (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);

Chacune de ces paires de fonctions possède également une macro sans le suffixe, cela dépend si la macro UNICODE est définie.

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

Pour que cela fonctionne, le type TCHAR est défini pour abstraire le type de caractère utilisé par les fonctions API.

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

Ceci, cependant, était une mauvaise idée . Vous devez toujours spécifier explicitement le type de caractère.

Ce que je ne comprends pas, c'est comment UTF-8 est conceptuellement différent d'un encodage MBCS?

MBCS signifie "jeu de caractères multi-octets". Pour les esprits littéraux, il semble que l'UTF-8 serait admissible.

Mais dans Windows, "MBCS" fait uniquement référence aux encodages de caractères qui peuvent être utilisés avec les versions "A" des fonctions de l'API Windows. Cela inclut les pages de codes 932 (Shift_JIS), 936 (GBK), 949 (KS_C_5601-1987) et 950 (Big5), mais [~ # ~] pas [~ # ~] UTF-8.

Pour utiliser UTF-8, vous devez convertir la chaîne en UTF-16 à l'aide de MultiByteToWideChar, appeler la version "W" de la fonction et appeler WideCharToMultiByte sur la sortie. C'est essentiellement ce que font réellement les fonctions "A", ce qui me fait me demander pourquoi Windows ne supporte pas seulement UTF-8 .

Cette incapacité à prendre en charge l'encodage de caractères le plus courant rend la version "A" de l'API Windows inutile. Par conséquent, vous devez toujours utiliser les fonctions "W" .

Unicode est un codage de caractères 16 bits

Cela annule tout ce que j'ai lu sur l'Unicode.

MSDN est incorrect. Unicode est un jeu de caractères codés sur 21 bits qui a plusieurs codages, les plus courants étant UTF-8, UTF-16 et UTF-32. (Il existe également d'autres encodages Unicode, tels que GB18030, UTF-7 et UTF-EBCDIC.)

Chaque fois que Microsoft fait référence à "Unicode", cela signifie vraiment UTF-16 (ou UCS-2). C'est pour des raisons historiques. Windows NT a été l'un des premiers à adopter Unicode, à l'époque où 16 bits étaient suffisants pour tout le monde, et UTF-8 n'était utilisé que sur le plan 9. Donc, UCS-2 était Unicode.

99
dan04

_MBCS et _UNICODE sont des macros pour déterminer la version des routines TCHAR.H à appeler. Par exemple, si vous utilisez _tcsclen pour compter la longueur d'une chaîne, le préprocesseur mapperait _tcsclen vers une version différente selon les deux macros: _MBCS et _UNICODE.

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

Pour expliquer la différence de ces fonctions de comptage de longueur de chaîne, considérez l'exemple suivant.
.

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

Le résultat serait 4 6 3.

Voici la représentation hexdécimale de I爱你M en GBK.

GBK:             49 B0 AE C4 E3 4D 00                

_mbslen sait que cette chaîne est encodée en GBK, elle pourrait donc interpréter la chaîne correctement et obtenir le bon résultat 4 mots: 49 comme I, B0 AE comme , C4 E3 comme , 4D comme M.

strlen ne connaît que 0x00, donc ça devient 6.

wcslen considère que ce tableau hexdeciaml est codé en UTF16LE et qu'il compte deux octets comme un seul mot, donc il obtient 3 mots: 49 B0, AE C4, E3 4D.

comme l'a souligné @xiaokaoy, le seul terminateur valide pour wcslen est 00 00. Ainsi, le résultat n'est pas garanti d'être 3 si l'octet suivant n'est pas 00.

16
Jichao

[~ # ~] mbcs [~ # ~] signifie Jeu de caractères multi-octets = et décrit tout jeu de caractères où un caractère est codé en (éventuellement) plus de 1 octet.

Les [~ # ~] ansi [~ # ~] / [~ # ~] ascii [~ # ~ ] les jeux de caractères ne sont pas multi-octets.

UTF-8 , cependant, est un codage à plusieurs octets. Il code tout caractère Unicode sous la forme d'une séquence de 1, 2, 3 ou 4 octets (octets).

Cependant, UTF-8 n'est qu'un parmi plusieurs codages concrets possibles du jeu de caractères Unicode. Notamment, UTF-16 en est un autre et s'avère être l'encodage utilisé par Windows/.NET (IIRC). Voici la différence entre UTF-8 et UTF-16:

  • UTF-8 code tout caractère Unicode sous la forme d'une séquence de 1, 2, 3 ou 4 octets.

  • UTF-16 code la plupart des caractères Unicode en 2 octets et certains en 4 octets.

Il est donc pas correct que Unicode est un codage de caractères 16 bits. C'est plutôt quelque chose comme un encodage 21 bits (voire plus de nos jours), car il englobe un jeu de caractères avec des points de code U+000000 Jusqu'à U+10FFFF.

10
stakx

En tant que note de bas de page pour les autres réponses, MSDN a un document Generic-Text Mappings in TCHAR.H avec des tableaux pratiques résumant comment les directives de préprocesseur _UNICODE et _MBCS modifient la définition des différents types C/C++.

En ce qui concerne le phrasé "Unicode" et "Jeu de caractères multi-octets", les gens ont déjà décrit les effets. Je veux juste souligner que ces deux éléments sont parlés par Microsoft pour des choses très spécifiques. (C'est-à-dire qu'ils signifient quelque chose de moins général et de plus particulier à Windows que ce à quoi on pourrait s'attendre s'ils proviennent d'une compréhension non spécifique de Microsoft de l'internationalisation de texte.) Ces phrases exactes apparaissent et ont tendance à avoir leurs propres sections/sous-sections distinctes de documents techniques Microsoft, par exemple dans Texte et chaînes dans Visual C++

4
Chris