我想确认一下我对原始字符串文字和Windows上的(非宽)execution character set
的理解。
我希望具体确认的相关段落以粗体显示但首先是一些背景。
背景
(相关问题见bold中的以下段落)
由于@TheUndeadFish对我昨天发布的这个问题的回答下面进行了有益的讨论,我试图理解确定Windows上MSVC中用作execution character set
的字符集和编码的规则(在execution character set
的C++规范意义上;请参阅@DietmarKühl的帖子)。
我怀疑有些人可能会认为,甚至费力地理解MSVC中非ASCII字符的char *
(即非宽)字符串的ANSI相关行为都是浪费时间
例如,考虑@IInspectable在此处的评论:
您不能在ANSI版本的Windows API,希望任何正常的事情都能发生。
请注意,在我当前基于Windows MFC的应用程序上的i18n项目中,我将删除对API调用的非宽(即ANSI)版本的所有调用,并且我希望编译器在内部生成execution wide-character set
字符串,NOTexecution character set
(非宽)字符串。
然而,我想理解现有的代码,该代码已经具有使用ANSI API函数的一些国际化功能即使有些人认为ANSI API在非ASCII字符串上的行为是疯狂的,我也想理解它。
我想和其他人一样,我发现很难在Windows上找到关于非宽execution character set
的澄清文档。
特别地,因为(非宽)execution character set
由C++标准定义为char
的序列(与wchar_t
相反),所以UTF-16不能在内部用于在非宽execution character set
中存储字符。在这个时代,通过UTF-8(一种基于char
的编码)编码的Unicode字符集将被用作execution character set
的字符集和编码,这是有道理的。据我所知,Linux就是这样。然而,遗憾的是,这不是在Windows上的情况,甚至是MSVC 2013。
这引出了我两个问题中的第一个。
问题#1:请确认我在下面的段落中是正确的。
在这种背景下,这是我的问题在MSVC(包括VS 2013)中,execution character set
似乎是(许多可能的)ANSI字符集之一,使用与特定给定ANSI字符集相对应的(许多可能)代码页之一来定义编码,而不是使用UTF-8编码的Unicode字符集(请注意,我询问的是非广域execution character set
。)这是正确的吗?
背景,继续(假设我在问题#1中是正确的)
如果我理解正确的话,以上粗体段落可以说是在Windows上使用ANSI API"疯狂"的主要原因。
具体来说,考虑一下"sane"的情况,即使用Unicode和UTF-8作为execution character set
。
在这种情况下,代码在哪台机器上编译、何时编译都无关紧要,代码在什么机器上运行、何时运行也无关紧要。字符串文字的实际原始字节将始终在Unicode字符集中以UTF-8作为编码进行内部表示,运行时系统将始终在语义上将此类字符串视为UTF-8。
在"疯狂"的情况下(如果我理解正确的话)就没有这样的运气了,在这种情况下,ANSI字符集和代码页编码被用作execution character set
。在这种情况下(Windows世界),与代码运行的机器相比,运行时行为可能会受到编译代码的机器的影响
这里是问题2:再次确认我在下面的段落中是正确的。
考虑到这一持续的背景,我怀疑:特别是,对于MSVC,execution character set
及其编码在某种程度上不太容易理解,取决于编译时编译器运行的机器上编译器选择的区域设置。这将确定"烧入"可执行文件的字符文字的原始字节。而且,在运行时,MSVC C运行库可能使用不同的execution character set
并进行编码,以解释烧入可执行文件的字符文本的原始字节我说得对吗?
(我可能会在某个时候为这个问题添加一些例子。)
最终评论
从根本上讲,如果我理解正确的话,上面粗体的段落解释了在Windows上使用ANSI API的"疯狂"。由于编译器选择的ANSI字符集和编码与C运行时选择的ANSI字符串集和编码之间可能存在差异,当程序中使用ANSI API时,字符串文字中的非ASCII字符可能不会像预期的那样出现在正在运行的MSVC程序中。
(请注意,ANSI的"疯狂"实际上只适用于字符串文字,因为根据C++标准,实际的源代码必须写在ASCII的子集中(编译器会丢弃源代码注释)。)
上面的描述是我目前对Windows上的ANSI API字符串文字的最佳理解。我想确认我的解释是正确的,我的理解是正确的。
这是一个很长的故事,我很难找到一个明确的问题。然而,我认为我可以解决导致这种情况的一些误解。
首先,"ANSI"是(窄)执行字符集的同义词。UTF-16是执行范围内的字符集。
编译器不会为您选择。如果使用窄的char
字符串,则编译器(运行时)知道它们是ANSI。
是的,特定的"ANSI"字符编码可能很重要。如果您在PC上编译L"ä"
文字,并且源代码在CP1252中,则该ä
字符将编译为UTF-16ä
。然而,同一字节可能是其他编码中的另一个非ASCII字符,这将导致不同的UTF-16字符。
但是请注意,只要MSVC以U+FEFF
"BOM"开头,它就完全能够编译UTF-8和UTF-16源代码。这使得整个理论问题几乎成为一个非问题。
[编辑]"特别是,对于MSVC,执行字符集及其编码取决于…">
不,MSVC实际上与执行字符集无关。char(0xE4)
的含义由操作系统决定。要查看此信息,请检查MinGW编译器。MinGW生成的可执行文件的行为与MSVC的相同,因为两者都针对相同的操作系统。