为什么在 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:

翻译语法规则中的优先级由下式指定 以下阶段。

物理源文件字符以
  1. 实现定义的方式映射到基本源字符集 (为行尾指示器引入换行符)if 必要。接受的物理源文件字符集为 实现定义。三元组序列([lex.trigraph])是 替换为相应的单字符内部表示形式。不在基本源字符集中的任何源文件字符 ([lex.charset]) 替换为通用字符名称 指定该字符。(实现可以使用任何内部 编码,只要在 源文件,以及源文件中表示的相同扩展字符 文件作为通用字符名称(即使用 \uXXXX 表示法), 等效处理,除非在 原始字符串文本。

这首先发生,因为正如您在评论中被告知的那样,三字形所代表的字符也需要可打印。

这种行为继承自 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éùè¨

最新更新