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

时间:2013-07-19 09:17:03

标签: c++ visual-studio winapi character-encoding

我正在使用遗留应用程序,而我正试图找出Multi byte character set选项下使用Not 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,单字节和多字节字符集代码页是可用的,还是只有多字节字符集代码页?我猜它必须支持欧洲语言。

谢谢,

安迪

进一步阅读

这些页面上的答案没有回答我的问题,但有助于我的理解: 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

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

并选择:

  • 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 74   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 74   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 74   00 == UTF-16 or UCS-2

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

Ultimate Conculsion

汉斯似乎是正确的,他说除了改变Win32 API以使用WA之外,定义对它没有任何魔力。因此,我无法真正看到Not SetMulti byte character set之间存在任何差异。

2 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:0)

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应用程序定义。有关更多信息,请参阅Generic-Text   Tchar.h中的映射。