为什么要在 Gnu gcc/g++ 中为三字母序列解析字符串文字?

Why are string literals parsed for trigraph sequences in Gnu gcc/g++?

考虑这个无害的 C++ 程序:

#include <iostream>
int main() {
  std::cout << "(Is this a trigraph??)" << std::endl;
  return 0;
}

当我使用 g++ 5.4.0 版编译它时,我得到以下诊断信息:

me@my-laptop:~/code/C++$ g++ -c test_trigraph.cpp
test_trigraph.cpp:4:36: warning: trigraph ??) ignored, use -trigraphs to enable [-Wtrigraphs]
   std::cout << "(Is this a trigraph??)" << std::endl;
                                     ^

程序运行,输出符合预期:

(Is this a trigraph??)

为什么要针对三字母解析字符串文字?

其他编译器也这样做吗?

三字母在翻译阶段 1 中处理(但在 C++17 中被删除)。字符串文字相关处理发生在后续阶段。正如 C++14 标准指定的 (n4140) [lex.phases]/1.1:

The precedence among the syntax rules of translation is specified by the following phases.

  1. Physical source file characters are mapped, in an implementation-defined manner, to the basic source character set (introducing new-line characters for end-of-line indicators) if necessary. The set of physical source file characters accepted is implementation-defined. Trigraph sequences ([lex.trigraph]) are replaced by corresponding single-character internal representations. Any source file character not in the basic source character set ([lex.charset]) is replaced by the universal-character-name that designates that character. (An implementation may use any internal encoding, so long as an actual extended character encountered in the source file, and the same extended character expressed in the source file as a universal-character-name (i.e., using the \uXXXX notation), are handled equivalently except where this replacement is reverted in a raw string literal.)

这是最先发生的,因为正如您在评论中所说,三字母代表的字符也需要可打印。

这种行为是从 C 编译器和过去使用串行终端时继承而来的,当时我们只使用了 7 位(第 8 位是奇偶校验位)。为了允许具有特殊字符的非英语语言(例如法语中的重音符号 àéèêîïôù 或西班牙语中的 ñ),ISO/IEC 646 代码页使用一些 ASCII(7 位)代码来表示它们。特别是代码 0x23、0x24(ASCII 中的#$)、0x40(@)、0x5B 到 0x5E([\]^)、0x60(`)和 0x7B 到 0x7E({|}~) 可以替换为国家变体1.

由于它们在 C 中具有特殊含义,因此可以仅使用 ISO 646 的不变部分在源代码中将它们替换为三字母。

出于兼容性原因,这一直保持到 C++14,那时只有恐龙还记得 ISO646 和 7 位代码页的(不太好)的日子。


1 例如使用的法语变体:0x23 £, 0x40 à 0x5B-0x5D °ç§, 0x60 µ, 0x7B-0x7E éùè¨