stringify 运算符如何扩展 TABS?

How does the stringify operator expand TABS?

GCC 似乎总是将源代码中的选项卡扩展 spaces。它保留表达式内的 space 。标准对此有何规定?

例如本例中c会包含什么(<TAB>表示源代码文件中的乱码\t字符)。

#define X(a) #a

const char* c = X(<TAB>a<TAB>c<TAB>);
// c == "a c" ? (looks like what gcc does)
// c == "a\tc" ?

查阅 C++ 标准(草案)的部分 [cpp.stringize] 告诉我们:

Each occurrence of whitespace between the stringizing argument's preprocessing tokens becomes a single space character in the character string literal. White space before the first preprocessing token and after the last preprocessing token comprising the stringizing argument is deleted.

给定:<TAB>a<TAB>c<TAB>,第一条规则意味着我们有 " a c ",但第二条规则意味着我们要删除前导和尾随空格,从而得到 "a c" 如你所见。

当前的 ISO CPP(C 预处理器)折叠其他答案中指定的空格。如 GCC docs 中所述,对预处理器使用 -traditonal-cpp 应保留空格

The form of horizontal whitespace in the input file is preserved in the output. In particular, hard tabs remain hard tabs. This can be useful if, for example, you are preprocessing a Makefile.

但这似乎也没有。所以,

$ cat test.cpp|grep 'const'|sed 's/\t/@/g'
   const char* c = X(@a@c@);

但在进行预处理时,标签会被替换

$ cpp test.cpp|grep 'const'|sed 's/\t/@/g'
   const char* c = "a c";

即使使用 traditional-cpp 选项也没有任何区别

$ cpp -traditional-cpp test.cpp|grep 'const'|sed 's/\t/@/g'
   const char* c = "a c";

这是使用 GNU 编译器集的输出。 clang 的情况并非如此,但它可以按预期使用 -traditional-cpp 选项

$clang -E -traditional-cpp test.cpp|grep 'const'|sed 's/\t/@/g'
   const char* c = #@a@c@;

这似乎是 GCC 中的错误。我在 WSL 上使用 GCC 9.3