Visual Studio 字符集“未设置”与“多字节字符集”
Posted
技术标签:
【中文标题】Visual Studio 字符集“未设置”与“多字节字符集”【英文标题】:Visual Studio Character Sets 'Not set' vs 'Multi byte character set' 【发布时间】:2013-07-18 12:29:01 【问题描述】:我正在使用旧版应用程序,我正在尝试找出在 Character Set
选项下使用 Multi byte character set
和 Not Set
编译的应用程序之间的区别。
我知道使用Multi byte character set
编译定义了_MBCS
,它允许使用多字节字符集代码页,而使用Not set
没有定义_MBCS
,在这种情况下只有单字节字符集代码页是允许的。
在使用Not Set
的情况下,我假设我们只能使用在此页面上找到的单字节字符集代码页:http://msdn.microsoft.com/en-gb/goglobal/bb964654.aspx
因此,我认为使用 Not Set
是否正确,应用程序将无法编码和写入或读取远东语言,因为它们是在双字节字符集代码页中定义的(当然还有 Unicode )?
接着,如果定义了Multi byte character
集,单字节和多字节字符集代码页都可用,还是只有多字节字符集代码页可用?我猜它必须同时支持欧洲语言。
谢谢,
安迪
进一步阅读
这些页面上的答案没有回答我的问题,但有助于我理解: About the "Character set" option in visual studio 2010
研究
所以,就像工作研究一样……我的语言环境设置为日语
对硬编码字符串的影响
char *foo = "Jap text: テスト";
wchar_t *bar = L"Jap text: テスト";
使用Unicode
编译
*foo = 4a 61 70 20 74 65 78 74 3a 20 83 65 83 58 83 67 == Shift-Jis (Code page 932) *bar = 4a 00 61 00 70 00 20 00 74 00 65 00 78 00 74 00 3a 00 20 00 c6 30 b9 30 c8 30 == UTF-16 or UCS-2
用Multi byte character set
编译
*foo = 4a 61 70 20 74 65 78 74 3a 20 83 65 83 58 83 67 == Shift-Jis (Code page 932) *bar = 4a 00 61 00 70 00 20 00 74 00 65 00 78 00 74 00 3a 00 20 00 c6 30 b9 30 c8 30 == UTF-16 or UCS-2
用Not Set
编译
*foo = 4a 61 70 20 74 65 78 74 3a 20 83 65 83 58 83 67 == Shift-Jis (Code page 932) *bar = 4a 00 61 00 70 00 20 00 74 00 65 00 78 00 74 00 3a 00 20 00 c6 30 b9 30 c8 30 == UTF-16 or UCS-2
结论: 字符编码对硬编码字符串没有任何影响。虽然如上定义 chars 似乎使用了 Locale 定义的代码页,而 wchar_t 似乎使用了 UCS-2 或 UTF-16。
在 W/A 版本的 Win32 API 中使用编码字符串
所以,使用以下代码:
char *foo = "C:\\Temp\\テスト\\テa.txt";
wchar_t *bar = L"C:\\Temp\\テスト\\テw.txt";
CreateFileA(bar, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
CreateFileW(foo, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
用Unicode
编译
结果:两个文件都已创建
使用Multi byte character set
编译
结果:两个文件都已创建
用Not set
编译
结果:两个文件都已创建
结论:
无论选择何种字符集,API 的A
和W
版本都需要相同的编码。由此,也许我们可以假设Character Set
选项所做的只是在 API 版本之间切换。所以A
版本总是需要当前代码页编码中的字符串,W
版本总是需要 UTF-16 或 UCS-2。
使用 W 和 A Win32 API 打开文件
所以使用下面的代码:
char filea[MAX_PATH] = 0;
OPENFILENAMEA ofna = 0;
ofna.lStructSize = sizeof ( ofna );
ofna.hwndOwner = NULL ;
ofna.lpstrFile = filea ;
ofna.nMaxFile = MAX_PATH;
ofna.lpstrFilter = "All\0*.*\0Text\0*.TXT\0";
ofna.nFilterIndex =1;
ofna.lpstrFileTitle = NULL ;
ofna.nMaxFileTitle = 0 ;
ofna.lpstrInitialDir=NULL ;
ofna.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST ;
wchar_t filew[MAX_PATH] = 0;
OPENFILENAMEW ofnw = 0;
ofnw.lStructSize = sizeof ( ofnw );
ofnw.hwndOwner = NULL ;
ofnw.lpstrFile = filew ;
ofnw.nMaxFile = MAX_PATH;
ofnw.lpstrFilter = L"All\0*.*\0Text\0*.TXT\0";
ofnw.nFilterIndex =1;
ofnw.lpstrFileTitle = NULL;
ofnw.nMaxFileTitle = 0 ;
ofnw.lpstrInitialDir=NULL ;
ofnw.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST ;
GetOpenFileNameA(&ofna);
GetOpenFileNameW(&ofnw);
并选择任一:
C:\Temp\テスト\テopenw.txt C:\Temp\テスト\テopenw.txt产量:
使用Unicode
编译时
*filea = 43 3a 5c 54 65 6d 70 5c 83 65 83 58 83 67 5c 83 65 6f 70 65 6e 61 2e 74 78 74 == Shift-Jis (Code page 932) *filew = 43 00 3a 00 5c 00 54 00 65 00 6d 00 70 00 5c 00 c6 30 b9 30 c8 30 5c 00 c6 30 6f 00 70 00 65 00 6e 00 77 00 2e 00 74 00 78 00 00 == UTF-16 or UCS-2
使用Multi byte character set
编译时
*filea = 43 3a 5c 54 65 6d 70 5c 83 65 83 58 83 67 5c 83 65 6f 70 65 6e 61 2e 74 78 74 == Shift-Jis (Code page 932) *filew = 43 00 3a 00 5c 00 54 00 65 00 6d 00 70 00 5c 00 c6 30 b9 30 c8 30 5c 00 c6 30 6f 00 70 00 65 00 6e 00 77 00 2e 00 74 00 78 00 00 == UTF-16 or UCS-2
使用Not Set
编译时
*filea = 43 3a 5c 54 65 6d 70 5c 83 65 83 58 83 67 5c 83 65 6f 70 65 6e 61 2e 74 78 74 == Shift-Jis (Code page 932) *filew = 43 00 3a 00 5c 00 54 00 65 00 6d 00 70 00 5c 00 c6 30 b9 30 c8 30 5c 00 c6 30 6f 00 70 00 65 00 6e 00 77 00 2e 00 74 00 78 00 00 == UTF-16 or UCS-2
结论:
同样,Character Set
设置与 Win32 API 的行为无关。 A
版本似乎总是返回一个带有活动代码页编码的字符串,而W
总是返回 UTF-16 或 UCS-2。我实际上可以在这个很棒的答案中看到这一点:https://***.com/a/3299860/187100。
终极结论
Hans 似乎是正确的,他说除了将 Win32 API 更改为使用 W
或 A
之外,定义并没有任何魔力。因此,我真的看不出Not Set
和Multi byte character set
之间有什么区别。
【问题讨论】:
【参考方案1】:reference 中声明:
根据定义,ASCII 字符集是所有字符集的子集 多字节字符集。在许多多字节字符集中,每个 0x00 – 0x7F 范围内的字符与 在 ASCII 字符集中具有相同的值。例如,在这两个 ASCII 和 MBCS 字符串,1 字节的 NULL 字符 ('\0') 具有 值为 0x00,表示终止空字符。
如您所料,通过启用_MBCS
,Visual Studio 也支持ASCII
单字符集。
在第二个reference,即使我们启用_MBCS
,似乎也支持单个字符集:
MBCS/Unicode 可移植性:使用 Tchar.h 头文件,您可以构建 来自相同来源的单字节、MBCS 和 Unicode 应用程序。 Tchar.h 定义了以 _tcs 为前缀的宏,映射到 str、_mbs 或 wcs 函数,视情况而定。要构建 MBCS,请定义符号 _MBCS。 要构建 Unicode,请定义符号 _UNICODE。默认情况下,_MBCS 是 为 MFC 应用程序定义。有关详细信息,请参阅通用文本 Tchar.h 中的映射。
【讨论】:
但是不使用_MBCS
是不是API 使用基于区域设置的单字节字符集代码页,例如在msdn.microsoft.com/en-gb/goglobal/bb964654.aspx 中定义的那些?因此,它们中的每一个都以 ASCII 范围开头,但它们也继续定义其他外来字符。
@Andy,是的,ASCII 是一个 7 位字符集,有 128 个字符,而单字节(8 位)区域设置编码可以编码 256 个字符。
是的,所以问题仍然存在,如果定义了 MBCS,是否排除了单字节字符集代码页(因此说泰语字符)?如果我在没有 MBSC 的情况下进行编译,我猜该应用程序将无法处理远东字符,因为它仅限于单字节字符集代码页>
@Andy,根据第二个参考,好像支持【参考方案2】:
不,这不是它真正的工作方式。唯一发生的事情是宏被定义,否则它不会对编译器产生神奇的影响。 非常很少真正编写使用#ifdef _MBCS
来测试这个宏的代码。
您几乎总是将其留给辅助函数来进行转换。像 WideCharToMultiByte()、OLE2A() 或 wctombs()。根据代码页的指导,它们是始终考虑多字节编码的转换函数。 _MBCS 是一个历史性的意外,仅在 25 多年前才相关,当时多字节编码还不常见。就像现在使用非 Unicode 编码也是一种历史产物一样。
【讨论】:
所以如果我理解正确,如果我定义了一个硬编码字符串,比如 char *foo = "テスト"。 foo 指向的字符串怎么不是由字符集设置定义的?也许包含该行的代码文件的编码? (我目前正在尝试测试这些理论) 这将强制您的文本编辑器为源代码文件选择适当的编码。本身就是事故的根源。如果它选择了 Unicode 编码,utf-8 很常见,你很可能会让你的编译器对此感到生气。 C4566 在我的机器上。只有当你住在日本并且不考虑很快搬家时才考虑这样写。 好的,听起来我现在对这一点有了更好的理解。定义并没有真正做太多,无论应用程序如何编译,代码页都是在机器上设置的,并且定义只是更改 Win32 API 并根据它是 W 还是 A,我猜它会返回页面代码(多字节或单字节字符集)编码的东西 (A) 还是 UTF-16 (W)?以上是关于Visual Studio 字符集“未设置”与“多字节字符集”的主要内容,如果未能解决你的问题,请参考以下文章
Visual Studio C ++组合框控件不适用于多字节字符集
网络核心连接字符串 Dapper Visual Studio 2017
从多字节字符集转换旧的Visual Studio C ++项目