【发布时间】: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://stackoverflow.com/a/3299860/187100。
终极结论
Hans 似乎是正确的,他说除了将 Win32 API 更改为使用 W 或 A 之外,定义并没有任何魔力。因此,我真的看不出Not Set 和Multi byte character set 之间有什么区别。
【问题讨论】:
标签: c++ visual-studio winapi character-encoding