Visual Studio字符集'未设置'与'多字节字符集'

And*_*ndy 12 c++ winapi character-encoding visual-studio

我正在使用遗留应用程序,我正在尝试解决使用Multi byte character setNot SetCharacter 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定义了set,​​单字节和多字节字符集代码页是可用的,还是只有多字节字符集代码页?我猜它必须支持欧洲语言.

谢谢,

安迪

进一步阅读

这些页面上的答案没有回答我的问题,但在我的理解中有所帮助: 关于visual studio 2010中的"字符集"选项

研究

所以,就像工作研究一样......我的语言环境设置为日语

对硬编码字符串的影响

char *foo = "Jap text: ???";
wchar_t *bar = L"Jap text: ???";
Run Code Online (Sandbox Code Playgroud)

用.编译 Unicode

*foo = 4a 61 70 20 74 65 78 74 3a 20 83 65 83 58 83 67 == Shift-Jis(代码页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或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(代码页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或UCS-2

用.编译 Not Set

*foo = 4a 61 70 20 74 65 78 74 3a 20 83 65 83 58 83 67 == Shift-Jis(代码页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或UCS-2

结论: 字符编码对硬编码字符串没有任何影响.虽然如上定义字符似乎使用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);
Run Code Online (Sandbox Code Playgroud)

用.编译 Unicode

结果:两个文件都已创建

用.编译 Multi byte character set

结果:两个文件都已创建

用.编译 Not set

结果:两个文件都已创建

结论: 无论选择哪个字符集,API的版本AW版本都需要相同的编码.从这一点,也许我们可以假设所有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);
Run Code Online (Sandbox Code Playgroud)

并选择:

  • 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(代码页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 74 00 == UTF-16或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(代码页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 74 00 == UTF-16或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(代码页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 74 00 == UTF-16或UCS-2

结论: 同样,该Character Set设置不会影响Win32 API的行为.该A版本似乎总是与活动代码页的编码和返回一个字符串W一个总是返回UTF-16或UCS-2.我实际上可以在这个很好的答案中看到这个解释:https://stackoverflow.com/a/3299860/187100.

终极结算

汉斯似乎是正确的,他说除了改变Win32 API以使用W或之外,定义并没有真正的魔力A.因此,我真的看不出Not Set和之间有任何区别Multi byte character set.

Han*_*ant 7

不,这不是它的工作方式.唯一发生的事情是宏被定义,否则它对编译器没有神奇的影响.实际上编写用于测试此宏的代码是非常罕见的#ifdef _MBCS.

您几乎总是将它留给辅助函数来进行转换.像WideCharToMultiByte(),OLE2A()或wctombs().在代码页的指导下,哪些是始终考虑多字节编码的转换函数._MBCS是一个历史性的事故,仅在25年多以前相关,当时多字节编码还不常见.就像使用非Unicode编码一样,这也是历史上的工件.