Różnica między MBCS i UTF-8 W Windows

Czytam o zestawie charater i kodowaniu w Windows. Zauważyłem, że w kompilatorze Visual Studio (dla C++) są dwie flagi kompilatora o nazwie MBCS i UNICODE. Jaka jest między nimi różnica ? Nie rozumiem, jak UTF-8 różni się koncepcyjnie od kodowania MBCS ? Ponadto znalazłem następujący cytat w MSDN:

Unicode jest 16-bitowym kodowaniem znaków

To neguje to, co czytałem o Unicode. Myślałem, że unicode może być kodowane różnymi kodowaniami, takimi jak UTF-8 i UTF-16. Czy ktoś może rzucić więcej światła na to zamieszanie?

Author: Naveen, 2010-07-21

4 answers

Zauważyłem, że istnieją dwa Kompilatory flagi w kompilatorze Visual Studio (dla C++) o nazwie MBCS i UNICODE. Co to jest różnica między nimi ?

Wiele funkcji w Windows API jest dostępnych w dwóch wersjach: jedna, która pobiera parametry char (na stronie kodowej) i jedna, która pobiera parametry wchar_t (w 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);

Każda z tych par funkcji ma również makro bez przyrostka, które zależy od tego, czy makro UNICODE jest zdefiniowany.

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

Aby to zadziałało, typ TCHAR jest zdefiniowany tak, aby wyodrębnić typ znaków używany przez funkcje API.

#ifdef UNICODE
    typedef wchar_t TCHAR;
#else
    typedef char TCHAR;
#endif
To jednak był zły pomysł. Zawsze należy wyraźnie określić typ znaku.

To czego nie rozumiem to jak jest UTF-8 koncepcyjnie różni się od MBCS kodowanie ?

MBCS oznacza "multi-bajtowy zestaw znaków". Dla dosłownych, wydaje się, że UTF-8 / align = "left" /

Ale w systemie Windows "MBCS" odnosi się tylko do kodowania znaków, które mogą być używane z wersjami" A " funkcji Windows API. Obejmuje To strony kodowe 932 (Shift_JIS), 936 (GBK), 949 (KS_C_5601-1987) i 950 (Big5), ale Nie} UTF-8.

Aby użyć UTF-8, musisz przekonwertować łańcuch znaków na UTF-16 za pomocą MultiByteToWideChar, wywołać wersję "W" funkcji i wywołać WideCharToMultiByte na wyjściu. To jest zasadniczo to, co funkcje "A" faktycznie zrobić, co sprawia, że zastanawiam się dlaczego Windows nie obsługuje tylko UTF-8.

Ta niemożność obsługi najczęstszego kodowania znaków sprawia, że wersja "A" Windows API jest bezużyteczna. Dlatego powinieneś zawsze używać funkcji " W " .

Unicode jest 16-bitowym kodowaniem znaków

To neguje to, co przeczytałem o Unicode.

MSDN się myli. Unicode to 21-bitowy kodowany zestaw znaków, który ma kilka kodowań, najbardziej UTF-8, UTF-16 i UTF-32. (Istnieją również inne kodowania Unicode, takie jak GB18030, UTF-7 i UTF-EBCDIC.)

Gdy Microsoft odnosi się do "Unicode", tak naprawdę oznacza UTF-16 (lub UCS-2). Dzieje się tak ze względów historycznych. Windows NT był wczesnym użytkownikiem Unicode, kiedy uważano, że 16 bitów wystarczy dla wszystkich, a UTF-8 był używany tylko na planie 9. Więc UCS-2 był Unicode.

 95
Author: dan04,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:25:34

_MBCS i _UNICODE są makrami określającymi, która wersja TCHAR.H100000000000 Na przykład, jeśli użyjesz _tcsclen do policzenia długości łańcucha, preprocesor zmapuje _tcsclen do innej wersji zgodnie z dwoma makrami: _MBCS i _UNICODE.

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

Aby wyjaśnić różnicę między tymi funkcjami liczenia długości łańcucha, rozważ poniższy przykład.
Jeśli masz komputer z systemem Windows Simplified Chinese edition, który używa GBK (936 code page), kompilujesz plik źródłowy zakodowany gbk i uruchom go.

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

Wynik będzie 4 6 3.

Oto szesnastkowa reprezentacja I爱你M w GBK.

GBK:             49 B0 AE C4 E3 4D 00                

_mbslen wie, że ten łańcuch jest zakodowany w GBK, więc może poprawnie go odtworzyć i uzyskać właściwy wynik 4 słowa: 49 jako I, B0 AE jako , C4 E3 jako , 4D jako M.

Strlen wie tylko 0x00, więc dostaje 6.

Wcslen rozważ, że tablica hexdeciaml jest zakodowana w UTF16LE i liczy dwa bajty jako jedno słowo, więc otrzymuje 3 słowa: 49 B0, AE C4, E3 4D.

Jak zauważył @xiaokaoy, jedynym poprawnym terminatorem dla wcslen jest 00 00. Tak więc wynik nie jest gwarantowany 3, Jeśli następujący bajt nie jest 00.

 14
Author: Jichao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-12 13:19:10

MBCS oznacza wielobajtowy zestaw znaków i opisuje dowolny zestaw znaków, w którym znak jest zakodowany w (ewentualnie) więcej niż 1 bajt.

ANSI / ASCII zestawy znaków nie są wielobajtowe.

UTF-8 jest kodowaniem wielobajtowym. Koduje dowolny znak Unicode jako sekwencję 1, 2, 3 lub 4 oktety (bajty).

UTF-8 jest jednak tylko jednym z kilku możliwych konkretnych kodowań Unicode zestaw znaków. UTF-16 jest innym kodowaniem używanym przez Windows/. NET (IIRC). Oto różnica między UTF-8 a UTF-16:

  • UTF-8 koduje dowolny znak Unicode jako sekwencję 1, 2, 3 lub 4 bajtów.

  • UTF-16 koduje większość znaków Unicode jako 2 bajty, a niektóre jako 4 bajty.

Jest zatem nie poprawne, że Unicode jest 16-bitowym kodowaniem znaków. To raczej coś w rodzaju 21-bitowego kodowania (a nawet więcej w dzisiejszych czasach), ponieważ obejmuje zestaw znaków z punktami kodu U+000000 do U+10FFFF.

 10
Author: stakx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-21 11:33:36

Jako przypis do innych odpowiedzi, MSDN ma dokument Generic-Text Mappings w TCHAR.H z przydatnymi tabelami podsumowującymi sposób, w jaki dyrektywy preprocesora _UNICODE i _MBCS zmieniają definicję różnych typów C/C++.

Jeśli chodzi o wyrażenia "Unicode" i "Multi-bajtowy zestaw znaków", ludzie już opisali, jakie są efekty. Chcę tylko podkreślić, że oba te rozwiązania są bardzo specyficzne dla Microsoftu. (Czyli oznaczają coś mniej ogólnego i bardziej specyficzny dla systemu Windows, niż można by się spodziewać, jeśli pochodzi z innego niż Microsoft rozumienia internacjonalizacji tekstu.) Te dokładne zwroty pojawiają się i mają tendencję do uzyskiwania osobnych sekcji / podrozdziałów dokumentów technicznych microsoft, np. w tekst i ciągi w Visual C++

 4
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-10 20:31:09