考虑这个无害的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??)
为什么要为三字符分析字符串文字呢?
其他编译器也这样做吗?
答案 0 :(得分:5)
Trigraphs在翻译阶段1处理(然而,它们在C ++ 17中被删除)。字符串文字相关处理在后续阶段发生。正如C ++ 14标准指定(n4140)[lex.phases]/1.1:
翻译语法规则的优先级由 以下阶段。
- 物理源文件字符以实现定义的方式映射到基本源字符集 (引入行尾指标的换行符)if 必要。接受的物理源文件字符集是 实现定义。 Trigraph sequence([lex.trigraph])是 由相应的单字符内部表示替换。 任何源文件字符都不在基本源字符集中 ([lex.charset])被通用字符名称替换 指定那个角色。 (实现可以使用任何内部 编码,只要遇到实际的扩展字符 源文件,以及源中表示的相同扩展字符 file作为通用字符名称(即使用\ uXXXX表示法), 处理相同,除非这个替换被还原 原始字符串文字。)
醇>
这首先发生了,因为正如你在评论中被告知的那样,三卦所代表的角色也需要打印。
答案 1 :(得分:1)
这种行为继承自C编译器和旧时代,当我们使用仅使用7位的串行终端时(第8位是奇偶校验位)。为了允许具有特殊字符的非英语语言(例如法语中的重音àéèêîïù或西班牙语中的ñ),ISO/IEC 646代码页使用一些ASCII(7位)代码来表示它们。特别是,代码0x23,0x24(ASCII中的#$
)0x40(@
),0x5B到0x5E([\]^
),0x60(`)和0x7B到0x7E({{1} })可以用国家变体 1 代替。
由于它们在C中具有特殊含义,因此只需使用ISO 646的不变部分就可以在源代码中使用三字符替换它们。
出于兼容性原因,只有恐龙仍然记得ISO646和7位代码页的(不太好)时,这一直保持到C ++ 14。
1 例如,使用的法语版本:0x23 {|}~
,0x40 £
0x5B-0x5D à
,0x60 °ç§
,0x7B- 0x7E µ