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.
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??M
GBK中的十六进制表示.
GBK: 49 B0 AE C4 E3 4D 00
Run Code Online (Sandbox Code Playgroud)
_mbslen知道这个字符串是用GBK编码的,所以它可以正确地解释字符串并获得正确的结果4
字:49
as I
,B0 AE
as ?
,C4 E3
as ?
,4D
as M
.
strlen只知道0x00
,所以它得到了6
.
wcslen考虑这个hexdeciaml阵列在utf16le应按编码,指望两个字节为一个字,所以它得到3
的话:49 B0
,AE C4
,E3 4D
.
正如@xiaokaoy指出的那样,唯一有效的终止符wcslen
是00 00
.因此,3
如果不跟随以下字节,则不保证结果00
.
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
.
作为其他答案的脚注,MSDN 有一个文档TCHAR.H 中的通用文本映射,其中包含方便的表格,总结了预处理器指令 _UNICODE 和 _MBCS 如何更改不同 C/C++ 类型的定义。
至于“Unicode”和“多字节字符集”的说法,人们已经描述了其效果。我只是想强调,这两者都是微软针对一些非常具体的事情所讲的。(也就是说,如果来自对文本国际化的非 Microsoft 特定理解,它们的含义对于 Windows 而言不那么普遍,而且比人们想象的更特殊。)这些确切的短语会出现,并且往往会获得自己单独的部分/小节微软技术文档,例如Visual C++ 中的文本和字符串