不同的字符集用来做什么

What are the different character sets used for?

本文关键字:什么 字符集      更新时间:2023-10-16

C++标准提到了多个不同的字符集。特别是,它提到了以下字符集:

  1. 在2.2[lex.phases]bullet 1中,提到了物理源文件字符及其到基本源字符集的映射
  2. 在2.2[lex.phases]中,提到了项目符号2执行字符集
  3. 在2.3[lex.charset]第3段中,提到了一个基本执行字符集和一个基本执行范围字符集
  4. 同一节2.3[lex.charset]3还提到了执行字符集全执行字符集
  5. 当读取或写入文件时,这些文件会使用其他字符集

所有这些不同的字符集都用于什么,它们之间的转换是如何完成的,这些值中的哪些取决于区域设置?特别是,字符串文字是如何表示的?

以下是编译器本身使用的不同字符集的分解(实际上,所有对标准的引用都是针对C++14的):

  1. 物理源文件字符是C++源中使用的字符。现在,这些代码很可能使用某些Unicode编码进行编码,例如UTF-8或UTF-16。如果您来自欧洲或美国背景,您可能使用的ASCII字符可以方便地以UTF-8进行相同编码(每个ASCII文件都是UTF-8文件,但不是相反)。物理源文件characters_也可能是一些不寻常的东西,比如EBCDIC
  2. 基本源字符集是编译器所使用的,至少在概念上是这样。它是由物理源文件字符产生的,并将它们映射到各自的基本字符,或映射到使用通用字符名表示物理源字符的基本字符序列(见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)

    物理源字符集和基本字符集之间的映射是实现定义的。

  3. 基本执行字符集基础执行范围字符集是能够表示由几个特殊字符扩展的基本源字符集的字符集:

    警报('\a')、退格('\b')、回车('\r')和空字符('\0')

    非宽版本和宽版本之间的区别在于字符是使用char还是wchar_t表示。

  4. 执行字符集全执行字符集[/em>是基本字符集和全基本字符集的实现定义扩展。2.3[lex.charset]第3段指出,执行字符集的附加成员和附加成员的值是特定于区域设置的。目前还不清楚引用的是哪个区域设置,但我怀疑编译过程中使用的区域设置是有意的。在任何情况下,执行字符集都是由实现定义的(同样根据2.3[lex.charset]第3段)。

  5. 字符和字符串文字最初使用基本源字符集表示,有些字符可能使用通用字符名。所有这些都在编译时转换为执行字符集。根据2.14.3[lex.con],可在执行字符集中表示为一个char的字符文字即可工作。如果需要多个char,则可能有条件地支持字符文字(并且它们的类型为int)。对于字符串文字,2.14.5[lex.string]中描述了转换。第9段指出,UTF-8字符串文字(例如u8"hello")会产生与UTF-8字符串的代码单元相对应的值序列。否则,字符和通用字符名的翻译与字符文字的翻译相同(特别是,它是实现定义的),尽管为窄字符串生成多字节序列的字符只会导致多个字符(这种情况下不需要支持字符文字)。

到目前为止,只考虑编译的结果。任何不是字符或字符串文字的字符都用于指定代码的作用。有趣的问题是文字发生了什么?文字基本上都被翻译成实现定义的表示。这是实现定义的,意味着它在某个地方记录了应该发生的事情,但不同的实现之间可能会有所不同。

当处理来自某个地方的字符或字符串时,这有什么帮助?读取的任何字符或字符串都会转换为相应的执行字符集。特别是,当读取文件时,所有字符都会转换为这种通用表示。当然,为了使这种转换工作,需要根据文件的编码设置用于读取文件的区域设置。如果没有明确提到区域设置,则使用由系统最初确定的全局区域设置。初始全局语言环境可能是基于用户偏好设置的,例如,不基于环境变量。如果读取的文件使用与此全局区域设置不同的编码,则需要使用与该文件的编码匹配的相应的不同区域设置。

相应地,当使用其中一个执行字符集编写字符时,这些字符集将根据当前语言环境指定的编码进行转换。同样,如果需要特定的编码,则可能需要替换区域设置。

所有这些有效地意味着,在程序内部,所有字符串和字符处理都使用实现定义的执行字符集进行。程序读取的所有字符都需要转换为该字符集,并且写入的所有字符从该执行字符集中的字符开始,并且需要适当地转换为外部编码。当然,在理想的设置中,执行字符集和外部表示之间的转换就是身份,例如,因为执行字符集使用UTF-8,而外部表示也使用UTF-8。相应地,对于执行范围的字符集,除了在这种情况下,将使用UTF-16(作为UTF-16的两种变体之一,可以使用大端序或小端序表示)。