三字符组(trigraphs)是由1989年的ANSI C标准引入的,后来所有的C标准都保留了它们(到目前为止,即将发布的C23标准将放弃它们)。它们也出现在1998年发布的第一个ISO C++标准中,并且在后来的所有C++标准中包括C++14。(感谢Jonathan Leffler和dyp查找细节并指出C++17版本已删除三字符组)。
引用C++17标准草稿:
对原始特性的影响:使用三字符组的有效C++2014代码可能在这个国际标准中无效或者具有不同的语义。如果它们出现在原始字符串字面值之外,实现可以选择按照C++2014中指定的方式翻译三字符组,作为从物理源文件字符到基本源字符集的实现定义映射的一部分。
在任一语言中,它们都不是可选功能(在C++17之前); 所有符合标准的编译器必须支持它们,并按照相应的语言标准进行解释。
例如,如果这个程序:
#include <stdio.h>
int main(void) {
if ('|' == '??!') {
puts("ok");
}
else {
puts("oops");
}
return 0;
}
如果输出了oops
,那么你的编译器就不符合规范。
但是许多C编译器默认情况下并不完全符合标准。只要编译器能够以某种方式符合标准,这对于标准来说就足够了。(gcc需要使用-pedantic
和-std=...
来实现这一点。)
即使编译器完全符合规范,标准也没有禁止编译器警告任何它喜欢的内容。符合规范的C编译器必须诊断任何语法规则或约束的违反,但它可以发出任意数量的额外警告 - 它不必区分必需的诊断和其他警告。
三字符组很少被使用。绝大多数开发系统直接支持三字符组替换的所有字符:#
、[
、\
、]
、^
、{
、|
、}
、~
。
事实上,三字符组被错误地使用的次数很可能比它们被正确使用的次数还要多:
fprintf(stderr, "What just happened here??!\n");
关于可能改变程序含义的三字符序列(相对于如果该语言没有三字符序列将会具有的含义)的警告,这是符合ISO标准并且在我的观点中也是非常合理的。大多数编译器可能都有选项来关闭此类警告。
相反地,对于一个不实现三字符序列的C++17编译器,警告那些在C++14或更早版本中被视为三字符序列的序列或提供支持三字符序列的选项都是合理的。同样,为禁用此类警告提供选项也是一件好事。
<
和{
。你和你的代码不太可能遇到这样的系统。 - user149341