c++编译器如何将转义序列转换为实际字节

how does c++ compiler convert escape sequence to actual bytes?

本文关键字:字节 转换 转义序列 编译器 c++      更新时间:2023-10-16

GCC编译器提供了一个编译器选项(-fexec-charset=option),因此您可以配置字符和字符串文字的编码,因此它将您的字符串从源字符集(默认为UTF-8)转换为执行字符集。

所以我想知道是从源字符集到执行字符集的这种转换导致转义序列被其相应的代码点所取代吗?

东西。

cout << "hello x60 "; // x60 replaced by byte 0x60
cout << "hello n"; // n replaced by 0xA0

在第一个例子中,这个字符x60是编码独立的,而在第二个例子中,这个字符'n'字节表示是编码相关的,也是平台相关的(它将在windows中变为rn,在UNIX中保持n)。

虽然你显然没有意识到这一点,但你实际上是在询问两个完全独立的转换。

第一个是在编译器中转换转义序列。这很简单——当它在(例如)一个字符串中看到时,它会查看下一个字符并为这两个字符产生一个字节的输出(或者,取决于确切的输入,它可能是从两个以上的输入字符中产生一个字节的输出,例如01)。

在Windows上从nrn的转换是完全分开的—这发生在输出到流期间—特别是文本模式流。这种转换根本不是由编译器完成的,而是由iostreams库中的代码完成的。

如果你真的关心第一个,这里是我几年前写的一些代码,它的功能与编译器大致相同(尽管有c++标签,但这段代码是纯C):

#include <string.h>
#include <stdio.h>
#include "snip_str.h"
char *translate(char *string)
{
      char *here=string;
      size_t len=strlen(string);
      int num;
      int numlen;
      while (NULL!=(here=strchr(here,'')))
      {
            numlen=1;
            switch (here[1])
            {
            case '':
                  break;
            case 'r':
                  *here = 'r';
                  break;
            case 'n':
                  *here = 'n';
                  break;
            case 't':
                  *here = 't';
                  break;
            case 'v':
                  *here = 'v';
                  break;
            case 'a':
                  *here = 'a';
                  break;
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
                  numlen = sscanf(here,"%o",&num);
                  *here = (char)num;
                  break;
            case 'x':
                  numlen = sscanf(here,"%x",&num);
                  *here = (char) num;
                  break;
            }
            num = here - string + numlen;
            here++;
            memmove(here,here+numlen,len-num );
      }
      return string;
}

在网上搜索后,我现在知道我问题的答案了。因此,我将尝试为那些对c++中处理转义序列的机制感到疑惑的人解释它。

当你在一个文件上写你的代码时,你指定你的文件字符集(Windows-1252, ISO-8859-1, UTF-8, UTF-16, UTF-16BE, UTF-16LE…),这将映射你的文件中的字符到他们相应的代码点,然后使用你指定的字符集编码到硬盘驱动器上保存的字节流。
当您尝试编译源代码文件时,如果您没有使用-finput-charset=option编译器选项指定文件编码,编译器将假设您的文件使用UTF-8编码。在这两种情况下,C PreProcessor (CPP)将做的第一件事是将文件转换为源字符集,即UTF-8。

CPP完成后,字符串和字符常量再次转换为执行字符集,默认情况下它匹配源字符集 UTF-8,但您可以使用-exec-charset=option编译器选项更改它。到目前为止,一切都很清楚,我们没有讨论转义序列,因为它们的处理方式不同。

当字符串从源字符集转换为执行字符集时,有两种转义序列,每种转义序列的处理方式不同。第一类是octal or hexadecimal转义序列,如xA1 or 45;第二类是escape sequence that get represented using a backslash followed by a character转义序列,如r or n

八进制和十六进制转义序列值独立于执行字符集,这意味着它们不会从源字符集转换为执行字符集,例如xA1的值A1与当前执行字符集无关。剩余的转义序列值取决于执行字符集,例如'n'将首先映射到源字符集中的相应字符,在这种情况下,它是UTF-8中的0A,然后转换为执行字符集,因此,例如,如果用户设置了-fexec-charset=UTF-16BE,那么'n'将是源字符集中的0A,然后在源到执行字符集转换后的00 0A

换行转义字符n甚至与平台相关,在windows操作系统中输出库将用rn=10 0A替换n=0A,在Unix中它将保持n=0A。注意,这个替换发生在字符和字符串从source charset转换到execution charset之后,否则我们将得到不同的结果。