Windows上MBCS和UTF-8的区别

Nav*_*een 58 windows unicode character-encoding mbcs

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

Unicode是一种16位字符编码

这否定了我读到的关于Unicode的任何内容.我认为unicode可以使用不同的编码进行编码,例如UTF-8和UTF-16.有人能否对这种混乱有所了解?

dan*_*n04 101

我注意到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);
Run Code Online (Sandbox Code Playgroud)

这些函数对中的每一个也都有一个没有后缀的宏,这取决于是否UNICODE定义了宏.

#ifdef UNICODE
   #define MessageBox MessageBoxW
#else
   #define MessageBox MessageBoxA
#endif
Run Code Online (Sandbox Code Playgroud)

为了使这项工作,TCHAR类型被定义为抽象出API函数使用的字符类型.

#ifdef UNICODE
    typedef wchar_t TCHAR;
#else
    typedef char TCHAR;
#endif
Run Code Online (Sandbox Code Playgroud)

然而,这是个坏主意.您应该始终明确指定字符类型.

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

MBCS代表"多字节字符集".对于字面意思,似乎UTF-8符合资格.

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

要使用UTF-8,您必须使用字符串转换为UTF-16 MultiByteToWideChar,调用函数的"W"版本,然后调用WideCharToMultiByte输出.这基本上就是"A"函数的实际功能,这让我想知道为什么Windows不仅仅支持UTF-8.

这种无法支持最常见的字符编码使得Windows API的"A"版本无用.因此,您应始终使用"W"功能.

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.

  • 他们是微软.历史是错误的.抵抗是徒劳的. (22认同)
  • "这是历史性的"我想知道为什么他们在之前的15年里没有修复他们的文件. (9认同)
  • 这是一个很好的读物:http://www.utf8everywhere.org/这个问题再次成为最重要的因为MBCS已经在VS2013(MFC)中被弃用了...... (6认同)
  • 我认为UTF-16和UCS-2之间仍然存在差异:UTF-16可以将字符扩展为总共32位,以定义不适合16位的字符.UCS-2只有16位,但是在SQL Server中使用UCS-2可以保留完整的UTF-16编码,因为它以两个16位字符存储扩展的32位UTF-16字符.如果我错了,请纠正我! (4认同)
  • @ErikHart:较旧版本的Windows将WCHAR字符串视为UCS-2,仅限于16位基本多语言平面(BMP).现代版本的Windows使用相同的API,但将WCHAR字符串视为UTF-16,它允许使用代理项对BMP之外的代码点进行编码.这不会给你一个完整的32位,但没关系.UTF-16为您提供从0到0x10FFFF的代码点,这是整个Unicode指令表.请注意,UTF-8也受限于(按标准)0-0x10FFFF,即使它采用的方案可以为您提供完整的32位范围. (3认同)

Jic*_*hao 16

_MBCS和_UNICODE是用于确定要调用哪个版本的TCHAR.H例程的宏.例如,如果_tcsclen用于计算字符串的长度,则预处理器将_tcsclen根据两个宏映射到不同的版本:_MBCS和_UNICODE.

_UNICODE & _MBCS Not Defined: strlen  
_MBCS Defined: _mbslen  
_UNICODE Defined: wcslen  
Run Code Online (Sandbox Code Playgroud)

要解释这些字符串长度计数功能的不同,请考虑以下示例.
如果您的计算机盒运行使用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"));
Run Code Online (Sandbox Code Playgroud)

结果将是4 6 3.

这是I??MGBK中的十六进制表示.

GBK:             49 B0 AE C4 E3 4D 00                
Run Code Online (Sandbox Code Playgroud)

_mbslen知道这个字符串是用GBK编码的,所以它可以正确地解释字符串并获得正确的结果4字:49as I,B0 AEas ?,C4 E3as ?,4Das M.

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

wcslen考虑这个hexdeciaml阵列在utf16le应按编码,指望两个字节为一个字,所以它得到3的话:49 B0,AE C4,E3 4D.

正如@xiaokaoy指出的那样,唯一有效的终止符wcslen00 00.因此,3如果不跟随以下字节,则不保证结果00.

  • 伟大的。但以我愚见,**wcslen((const wchar_t*)"I爱你M")**的返回值并不能保证为3。如果不遵循**49 B0 AE C4 E3 4D 00**通过字节 00,**wcslen** 将返回大于 3 的值。 (2认同)
  • ****"我爱你M"**保证以**4D 00 00 00**结束.但**(const wchar_t*)"我爱你M"**不是. (2认同)
  • 只是一个写作问题,`_UNICODE&_MBCS Not Defined:strlen`应该写成`两个_UNICODE&_MBCS Not Defined:strlen`.因为我认为这意味着`_UNICODE已定义且_MBCS未定义:strlen`. (2认同)

sta*_*ica 10

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+000000最多的字符集U+10FFFF.

  • Windows NT仅支持UCS-2.自Windows 2000,IIRC以来,Windows支持完整的UTF-16. (5认同)
  • 这个答案是正确的,但要理解Microsoft文档,您需要认识到MSDN以特定方式使用其中一些术语,这些方式与其通常接受的字面含义不同.当MSDN说**Unicode**时,它们意味着**UTF-16**(或者,在真正的旧版本中,UCS-2).当MSDN说**ANSI代码页**时,它们意味着**Windows代码页**,其中大多数是单字节的,但其中一些(例如950)确实是**MBCS**.有一种"UTF-8代码页"(65001),但除了在UTF-8和UTF-16之间进行转换之外,它没有得到很好的支持. (3认同)
  • 可以,但是在Windows API文档中,它们使用Unicode表示UTF-16。(我怀疑对此的支持是有限的,并且假定UCS-2更安全。)是的,Unicode标准超出了21位。 (2认同)
  • 那篇文档可能会让它看起来好像是UTF-16,但这不正确(如果有的话,那就是另一种方式).UTF-16只是Unicode的一个_encoding_.是的,实际上它们实际上可能意味着UCS-2,而不是UTF-16.我对此并不完全确定. (2认同)

Chr*_*ris 5

作为其他答案的脚注,MSDN 有一个文档TCHAR.H 中的通用文本映射,其中包含方便的表格,总结了预处理器指令 _UNICODE 和 _MBCS 如何更改不同 C/C++ 类型的定义。

至于“Unicode”和“多字节字符集”的说法,人们已经描述了其效果。我只是想强调,这两者都是微软针对一些非常具体的事情所讲的。(也就是说,如果来自对文本国际化的非 Microsoft 特定理解,它们的含义对于 Windows 而言不那么普遍,而且比人们想象的更特殊。)这些确切的短语会出现,并且往往会获得自己单独的部分/小节微软技术文档,例如Visual C++ 中的文本和字符串