Windows上MBCS和UTF-8的区别

我正在阅读有关Windows上的字符集和编码。 我注意到在Visual Studio编译器(用于C ++)中有两个名为MBCS和UNICODE的编译器标志。 他们有什么区别? 我没有得到的是UTF-8如何在概念上与MBCS编码不同? 另外,我在MSDN中find下面的引用:

Unicode是一个16位字符编码

这就否定了我所读到的有关Unicode的内容。 我以为unicode可以编码不同的编码,如UTF-8和UTF-16。 有人可以更多地了解这种混乱吗?

我注意到在Visual Studio编译器(用于C ++)中有两个名为MBCS和UNICODE的编译器标志。 他们有什么区别?

Windows API中的许多函数有两个版本:一个采用char参数(在特定于语言环境的代码页中),另一个采用wchar_t参数(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); 

每个函数对都有一个没有后缀的macros,这取决于是否定义了UNICODEmacros。

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

为了使这个工作, TCHARtypes被定义为抽象出API函数使用的字符types。

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

但是,这是一个坏主意 。 您应该始终明确指定字符types。

我没有得到的是UTF-8如何在概念上与MBCS编码不同?

MBCS代表“多字节字符集”。 对于字面意思,似乎UTF-8将有资格。

但在Windows中,“MBCS”只是指可与“A”版Windows API函数一起使用的字符编码。 这包括代码页932(Shift_JIS),936(GBK),949(KS_C_5601-1987)和950(Big5),但不是 UTF-8。

要使用UTF-8,必须使用MultiByteToWideChar将string转换为UTF-16,调用函数的“W”版本,并在输出中调用WideCharToMultiByte 。 这实际上是“A”function实际上做什么,这让我想知道为什么Windows不只是支持UTF-8 。

这种无法支持最常见的字符编码使得Windows API的“A”版本无用。 因此,您应该始终使用“W”function

Unicode是一个16位字符编码

这就否定了我所读到的有关Unicode的内容。

MSDN是错误的。 Unicode是一种具有多种编码的21位编码字符集,最常见的是UTF-8,UTF-16和UTF-32。 (还有其他Unicode编码,例如GB18030,UTF-7和UTF-EBCDIC。

每当微软提到“Unicode”,他们的确是指UTF-16(或UCS-2)。 这是历史原因。 Windows NT是Unicode的早期采用者,当16位被认为对每个人都是足够的时候,而UTF-8只在Plan 9上使用。所以UCS-2 Unicode。

_MBCS和_UNICODE是macros来确定调用哪个版本的TCHAR.H例程。 例如,如果使用_tcsclen来计算string的长度,则预处理器会根据_tcsclen和_UNICODE这两个macros将_tcsclen映射到不同的版本。

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

为了解释这些string长度计数函数的差异,请考虑以下示例。
如果你有一个使用GBK(936代码页)运行Windows简体中文版的电脑盒,你可以编译一个gbk文件编码的源文件并运行它。

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

结果将是4 6 3

这里是GBK中I爱你M的hex表示。

 GBK: 49 B0 AE C4 E3 4D 00 

_mbslen知道这个string是用GBK编码的,所以它可以正确地解释string并得到正确的结果4字: 49IB0 AEC4 E3 M

strlen只知道0x00 ,所以得到6

wcslen认为这个hexdeciaml数组是用UTF16LE编码的,它将两个字节作为一个字来计算,所以得到3字: 49 B0AE C4E3 4D

正如@xiaokaoy所指出的那样, wcslen唯一有效的终结者是00 00 。 因此,如果后面的字节不是00 ,结果不保证为3

MBCS表示多字节字符集,并描述字符编码(可能)超过1个字节的任何字符集。

ANSI / ASCII字符集不是多字节。

但是, UTF-8是一个多字节编码。 它将任何Unicode字符编码为1,2,3或4个八位字节(字节)的序列。

但是,UTF-8只是Unicode字符集的几种可能的具体编码之一。 值得注意的是,UTF-16是另外一个,恰好是Windows / .NET(IIRC)使用的编码。 以下是UTF-8和UTF-16的区别:

  • UTF-8将任何Unicode字符编码为1,2,3或4字节的序列。

  • UTF-16将大多数Unicode字符编码为2个字节,有些则为4个字节。

因此,Unicode是16位字符编码是正确的。 它相当于21位编码(甚至更多),因为它包含了代码点U+000000U+10FFFF的字符集。

作为其他答案的脚注,MSDN 在TCHAR.H中有一个文档Generic-Text Mappings,其中总结了预处理器指令_UNICODE和_MBCS如何更改不同C / C ++types的定义。

对于“Unicode”和“多字节字符集”的措辞,人们已经描述了效果。 我只想强调,这两个人都是微软公司为一些非常具体的事情发言。 (也就是说,如果来自非微软特定的文本国际化理解,那么它们就意味着某种不那么一般和更特别的Windows。)那些精确的短语出现并倾向于得到自己独立的章节/小节Microsoft技术文档,例如在Visual C ++中的文本和string