我正在阅读关于Windows上的字符集和编码。我注意到Visual Studio编译器(用于C ++)中有两个编译器标志,称为MBCS和UNICODE。他们之间有什么区别?我没有得到的是UTF-8在概念上与MBCS编码有何不同?另外,我在MSDN中找到了以下引用:
Unicode是一个16位字符编码
这否定了我读到的有关Unicode的内容。我认为unicode可以使用不同的编码进行编码,例如UTF-8和UTF-16。有人可以对这种混乱有所了解吗?
答案 0 :(得分:97)
我注意到有两个编译器 Visual Studio编译器中的标志(for C ++)称为MBCS和UNICODE。什么是 他们之间的区别?
Windows API中的许多函数有两个版本:一个采用char
参数(在特定于语言环境的代码页中),另一个采用wchar_t
参数(采用UTF-16)。 / p>
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);
这些函数对中的每一个都有一个没有后缀的宏,这取决于是否定义了UNICODE
宏。
#ifdef UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif
为了使这项工作,TCHAR
类型被定义为抽象出API函数使用的字符类型。
#ifdef UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif
然而,was a bad idea。您应该始终明确指定字符类型。
我没有得到的是UTF-8是怎样的 概念上不同于MBCS 编码?
MBCS代表“多字节字符集”。对于字面意思,似乎UTF-8符合条件。
但在Windows中,“MBCS”仅指可与Windows API函数的“A”版本一起使用的字符编码。这包括代码页932(Shift_JIS),936(GBK),949(KS_C_5601-1987)和950(Big5),但 NOT UTF-8。
要使用UTF-8,您必须使用MultiByteToWideChar
将字符串转换为UTF-16,调用函数的“W”版本,并在输出上调用WideCharToMultiByte
。这基本上就是“A”函数的实际功能,这让我想起why Windows doesn't just support UTF-8。
无法支持the most common character encoding使得Windows API的“A”版本无法使用。因此,您应始终使用“W”功能。
Unicode是一个16位字符编码
这否定了我读到的任何内容 的Unicode。
MSDN错了。 Unicode是一个21位编码字符集,具有多种编码,最常见的是UTF-8,UTF-16和UTF-32。 (还有其他Unicode编码,例如GB18030,UTF-7和UTF-EBCDIC。)
每当Microsoft引用“Unicode”时,它们的确意味着UTF-16(或UCS-2)。这是出于历史原因。 Windows NT是Unicode的早期采用者,当16位被认为对每个人都足够时,UTF-8仅用于Plan 9.所以UCS-2 是 Unicode。
答案 1 :(得分:16)
_MBCS和_UNICODE是用于确定要调用哪个版本的TCHAR.H例程的宏。例如,如果使用_tcsclen
来计算字符串的长度,则预处理器会根据两个宏将_tcsclen
映射到不同的版本:_MBCS和_UNICODE。
_UNICODE & _MBCS Not Defined: strlen
_MBCS Defined: _mbslen
_UNICODE Defined: wcslen
要解释这些字符串长度计数功能的不同,请考虑以下示例 如果您的计算机包运行使用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
的十六进制表示。
GBK: 49 B0 AE C4 E3 4D 00
_mbslen知道这个字符串是用GBK编码的,所以它可以正确地解释字符串并得到正确的结果4
字:49
为I
,B0 AE
为{ {1}},爱
为C4 E3
,你
为4D
。
strlen只知道M
,因此得到0x00
。
wcslen认为这个hexdeciaml数组是以UTF16LE编码的,它将两个字节计为一个单词,因此得到6
个单词:3
,49 B0
,AE C4
。
正如@xiaokaoy所指出的,E3 4D
唯一有效的终结符是wcslen
。因此,如果以下字节不是00 00
,则不保证结果为3
。
答案 2 :(得分:10)
MBCS 表示Multi-Byte Character Set,并描述将字符编码为(可能)超过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
的字符集。
答案 3 :(得分:4)
作为其他答案的脚注,MSDN有一个文档Generic-Text Mappings in TCHAR.H,其中包含方便的表格,总结了预处理程序指令_UNICODE和_MBCS如何更改不同C / C ++类型的定义。
对于短语“Unicode”和“多字节字符集”,人们已经描述了效果是什么。我只想强调一下,这些都是微软代表一些非常具体的事情。 (也就是说,如果来自非Microsoft特定的对文本国际化的理解,那么它们意味着不那么通用且比Windows更具特异性。)这些确切的短语出现并倾向于获得他们自己的单独部分/子部分微软技术文档,例如在Text and Strings in Visual C++