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 setNot 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 的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 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 更改为使用 WA 之外,定义并没有任何魔力。因此,我真的看不出Not SetMulti 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 ++项目

Visual Studio 的字符集编码

visual studio的unicode怎么这么恶心啊,我想砸电脑了!

在Visual STudio 2017中对文件设置构建操作