C ++标准提到了多个不同的字符集。特别是,它提到了以下字符集:
这些不同的字符集用于什么,它们之间的转换是如何完成的,以及这些值中的哪些取决于区域设置?特别是,如何表示字符串文字?
答案 0 :(得分:10)
以下是编译器本身使用的不同字符集的细分(所有对标准的引用实际上都是C++14):
基本源字符集是编译器(至少在概念上)消耗的内容。它由物理源文件字符生成,并使用通用字符名称将它们映射到各自的基本字符或表示物理源字符的基本字符序列(请参阅2.2 [lex.phases])第1段)。基本的源字符集只是一组96个字符(2.3 [lex.charset]第1段):
a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 _ {} []#()< > %:; 。 ? * + - / ^& | 〜! =,\" “
和5个特殊字符空格(''),水平制表符(\ t),垂直制表符(\ v),换页符(\ f)和换行符(\ n)
物理源字符集和基本字符集之间的映射是实现定义的。
基本执行字符集和基本执行宽字符集是能够表示由少数特殊字符扩展的基本源字符集的字符集:
提醒(' \ a'),退格(' \ b'),回车(' \ r')和空字符(&# 39; \ 0&#39)
非宽版和宽版之间的区别在于是使用char
还是wchar_t
来表示字符。
执行字符集和执行宽字符集是基本字符集和基本宽字符集的实现定义扩展。在2.3 [lex.charset]第3段中,声明附加成员和执行字符集的附加成员的值是特定于语言环境的。不清楚引用哪个区域设置但我怀疑编译期间使用的区域设置是有意义的。在任何情况下,执行字符集都是实现定义的(同样根据2.3 [lex.charset]第3段)。
字符和字符串文字最初使用基本源字符集表示,其中一些字符可能使用通用字符名称。所有这些都在编译时转换为执行字符集。根据2.14.3 [lex.ccon]字符文字可以表示为执行字符集中的一个char
。如果需要多个char
,则可以有条件地支持字符文字(并且它们具有类型int
)。对于字符串文字,转换在2.14.5 [lex.string]中描述。第9段指出UTF-8字符串文字(例如u8"hello"
)导致一系列值对应于UTF-8字符串的代码单元。否则,字符和通用字符名称的翻译与字符文字的翻译相同(特别是,它是实现定义的),尽管导致窄字符串的多字节序列的字符只会导致多个字符(这种情况不是't&t; t对字符文字的必要支持。)
到目前为止,只考虑了编译的结果。任何不属于字符或字符串文字的字符都用于指定代码的作用。有趣的问题是文字发生了什么?文字基本上都被翻译成实现定义的表示。这是实现定义意味着它在某处记录了应该发生的事情,但它可以在不同的实现之间有所不同。
在处理来自某个地方的字符或字符串时,它有何帮助?好吧,任何读取的字符或字符串都将转换为相应的执行字符集。特别是,当读取文件时,所有字符都转换为此公共表示。当然,要使此转换起作用,需要根据该文件的编码来设置用于读取文件的语言环境。如果未明确提及区域设置,则使用最初由系统确定使用的全局区域设置。初始全局区域设置可能基于用户偏好以某种方式设置,例如,不基于环境变量。如果读取的文件使用的编码与此全局区域设置不同,则需要使用与文件编码匹配的相应不同区域设置。
相应地,当使用其中一个执行字符集写入字符时,这些字符集将根据当前语言环境指定的编码进行转换。同样,如果需要特定的编码,可能需要替换语言环境。
所有这些实际上意味着在程序内部使用实现定义的执行字符集进行所有字符串和字符处理。程序读取的所有字符都需要转换为该字符集,并且所有写入的字符在此执行字符集中以字符开头,需要适当地转换为外部编码。如果当然,在理想的设置中,执行字符集和外部表示之间的转换是标识,例如,因为执行字符集使用UTF-8并且外部表示也使用UTF-8。相应地,对于执行宽字符集,除了在这种情况下将使用UTF-16(两种变体之一,因为UTF-16可以使用big endian or little endian表示)。