为什么我们从MultiByte转换为WideChar
Why we convert from MultiByte to WideChar?
我习惯于处理ASCII字符串,但现在使用UNICODE,我对一些术语太困惑了:
什么是多字节字符,什么是widechar
有什么区别?多字节是指内存中包含多个字节的字符,而widechar
只是表示它的数据类型吗?
- 为什么要从
MultiByteToWideChar
和WideCharToMultiByte
转换
如果我声明这样的东西:
wchar_t* wcMsg = L"مرحبا";
MessageBoxW(0, wcMsg, 0, 0);
如果我定义了UNICODE
,它会正确打印消息。但为什么我没有从WideCharToMultiByte
转换到这里??
我的项目中的字符集
_MBCS
和UNICODE
之间有什么区别?MSDN让我对"Windows API"感到困惑的最后一件事是UTF-16。
有人能举例说明吗。非常感谢您的澄清。
ASCII字符串的字符宽度为一个字节(通常为8位,很少为7、9或其他位宽)。这是当时的遗留问题,当时内存大小非常小且昂贵,而且处理器通常只能处理每条指令一个字节。
很容易想象,到目前为止,一个字节还不足以存储世界上所有可用的字形。仅中文就有87.000个字形。一个字符通常只能处理256个字形(在一个8位字节中)。ASCII只定义了96个字形(加上下面的32个字符,这些字符被定义为不可打印的控制字符),这使它成为一个7位字符集。这对于英语的上下字符、数字、一些标点符号和其他字形来说已经足够了。ASCII不使用公共8位字节中的最高位。
要处理超过一个字节所能容纳的字形,一种方法是将基本字形存储在一个字节中,将其他常见字形存储在两个字节中;将很少使用的字形存储在3个甚至更多个字节中。这种方法被称为多字节字符集或可变宽度编码。一个非常常见的例子是UTF 8,它为一个字符使用1到4个字节。它将ASCII字符集存储在一个字节中(因此它也向后兼容ASCII)。最高的位被定义为一个开关:如果设置了它,其他字节将紧随其后。这同样适用于以下字节,从而形成最多4个字节的"链"。可变宽度字符集的优点是:
- 与7位ASCII字符集的向后兼容性
- 内存友好-使用尽可能少的内存
缺点是:
- 处理起来更困难,处理器成本更高。您不能简单地迭代一个字符串并假设每个
myString[n]
提供一个字形;相反,如果后面有更多字节,则必须计算每个字节
另一种方法是将每个字符存储在由n个字节组成的固定长度单词中,该单词足够宽,可以容纳所有可能的字形。这被称为固定宽度字符集;所有字符都有相同的宽度。一个众所周知的例子是UTF32。它是32位宽的,可以在一个单词中存储所有可能的字符。固定宽度字符集的赞成和反对显然与可变宽度字符集相反:内存很重,但更容易迭代。
但微软甚至在UTF32问世之前就选择了他们的原生字符集:他们使用UTF16作为Windows的字符集,Windows使用至少2字节(16位)的字长。这足够大,可以存储比单字节字符集多得多的字形,但不是所有的字形。考虑到这一点,微软对"多字节"answers"Unicode"的区分在今天有点误导,因为他们的Unicode实现也是一个多字节字符集——只是一个字形的最小大小更大。有人说这是一个很好的折衷方案,也有人说它是两个世界中最糟糕的-无论如何,事实就是这样。在当时(Windows NT),它是唯一可用的Unicode字符集,从这个角度来看,多字符和Unicode之间的区别在当时是正确的(见Raymond Chen的评论)
当然,如果你想把一个编码(比如说UTF8)中的字符串转换成另一个编码,比如说UTF16,你必须转换它们。这就是MultiByteToWideChar
为您所做的,WideCharToMultiByte
反之亦然。还有一些其他的转换函数和库。
这种转换花费了相当多的时间,因此得出的结论是:如果您大量使用字符串和系统调用,为了性能起见,您应该使用操作系统的本机字符集,在您的情况下,它将是UTF16。
因此,对于字符串处理,您应该选择wchar_t
,在Windows的情况下,它意味着UTF16。不幸的是,wchar_t
的宽度可能因编译器而异;在Unix下它通常是UTF32,在Windows下它是UTF16。
_MBCS
是一个自动预处理器定义,它告诉您已将字符集定义为多字节,UNICODE
告诉您已将其设置为UTF16。
你可以写
wchar_t* wcMsg = L"مرحبا";
MessageBoxW(0, wcMsg, 0, 0);
即使在没有UNICODE
定义集的程序中也是如此。L"
前缀定义,您的字符串是一个UNICODE
(宽字符)字符串,您可以用它调用系统函数
不幸的是,你不能写
char* msg = u8"مرحبا";
MessageBoxA(0, msg, 0, 0);
在C++11中,字符集支持得到了改进,因此您还可以通过前缀u8
将字符串定义为UTF8。但是带有"A"后缀的windows函数不理解UTF8,至少在windows 10 Build 17035之前是这样(参见tambre的评论)(另请参见https://stackoverflow.com/a/504789/2328447)这也建议在Windows/Vistudio下使用UTF16,也就是UNICODE。
将您的项目设置为"使用多字节字符集"或"使用Unicode字符集"也会更改许多其他依赖于字符的定义:最常见的是宏TCHAR
、_T()
和所有不带后缀的依赖于字符串的Windows函数,例如MessageBox()
(不带W
或A
后缀)如果您将项目设置为"使用多字节字符集",则TCHAR
将扩展为char
,_T()
将扩展为零,并且Windows函数将附加A
后缀。如果您将项目设置为"使用Unicode字符集",则TCHAR
将扩展为wchar_t
,_T()
将扩展到L
前缀,并且Windows函数将附加W
后缀。
这意味着,写
TCHAR* msg = _T("Hello");
MessageBox(0, msg, 0, 0);
将使用多字节字符集或unicode集对两者进行编译。您可以在MSDN上找到一些关于这些主题的全面指南。
不幸的是
TCHAR* msg = _T("مرحبا");
MessageBox(0, msg, 0, 0);
当选择"使用多字节字符集"时仍然无法工作-Windows函数仍然不支持UTF8,甚至会收到一些编译器警告,因为您定义了unicode字符,这些字符包含在未标记为unicode的字符串中(_T()
不会扩展为u8
)
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中使用nlohmann从类到json的转换
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- 复制列表初始化的隐式转换的等级是多少
- 正在将指针转换为范围
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 是否可以从int转换为enum类类型
- 为什么我们从MultiByte转换为WideChar
- 如何在 mfc 应用程序中从 api MultiByteToWideChar 将日语字符串转换为 widechar