为什么三字母在现代C ++编译器中会产生错误?

使用Turbo C ++编译的三字符程序的屏幕截图

即使在GCC编译器中,如果没有明确指定trigraph属性,也不会编译三字符。

#include int main() { int a=4; if((a==4) ??! (a==5)) printf("\nHello world!"); return 0; } 

保存为try.c的程序仅在我们指定gcc -Wall -trigraphs try.c时才在GCC编译器中编译,它仍然显示警告。 你可以招募一些能够处理和处理三字符而没有任何错误或警告的编译器吗?

Trigraphs由1989 ANSI C标准引入,并保留在所有后来的C标准中。 它们也出现在1998年出版的第一个ISO C ++标准中,以及高达C ++ 14的所有后来的C ++标准中。 (Trigraphs将在C ++中删除17.感谢Jonathan Leffler和dyp追踪细节。)

它们不是任何一种语言的可选function; 所有符合要求的编译器必须支持它们并按照相应的语言标准对其进行解释。

例如,如果这个程序:

 #include  int main(void) { if ('|' == '??!') { puts("ok"); } else { puts("oops"); } return 0; } 

打印oops ,然后你的编译器不符合。

但许多(可能是大多数)C编译器默认情况下并不完全符合。 只要编译器能够以某种方式符合标准,就标准而言,这就足够了。 (gcc需要-pedantic-std=...才能这样做。)

但即使编译器完全符合,标准中也没有任何内容禁止编译器警告它喜欢的任何内容。 符合标准的C编译器必须诊断任何违反语法规则或约束的行为,但它可以发出任意数量的附加警告 – 并且无需区分所需的诊断和其他警告。

Trigraphs很少使用。 绝大多数开发系统直接支持三字符替换的所有字符: #[\]^{|}~

实际上,有可能比使用正确使用三角戟更频繁地使用三角戟:

 fprintf(stderr, "What just happened here??!\n"); 

关于可能改变程序含义的三字母的警告(相对于语言没有三字母时的含义)是ISO标准和恕我直言都完全合理的。 大多数编译器可能有选项来关闭此类警告。

相反,对于实现三字符的C ++ 17编译器,警告在C ++ 14或更早版本中被视为三字符的序列是合理的。 同样,禁用此类警告的选项将是一件好事。

GCC对三卦过敏。 您必须明确启用它们:

 gcc -trigraphs ... 

GCC 4.7.1手册说:

-trigraphs

支持ISO C三字符。 -ansi选项(以及严格ISO C一致性的-std选项)暗示-trigraphs

它还说:

-Wtrigraphs

如果遇到任何可能改变程序含义的三字符,则发出警告(注释中的三字符不会被警告)。 -Wall启用此警告。

它们可能默认关闭 。

“有些编译器支持关闭三元组识别的选项,或默认禁用三元组,并需要一个选项才能打开它们”

海湾合作委员会可能是后者之一 。 虽然默认情况下应该忽略警告 ,但在这种情况下忽略可能会导致编译错误

Trigraph在编译的早期阶段进行转换,甚至可以用字符串文字替换。 这使得由三字母翻译引起的错误很难检测到 (如果您考虑使用日志进行调试并且在源中找到输出,则会出现最糟糕的情况)。

您看到的警告将帮助您快速发现可能的罪魁祸首,以跟踪错误的来源。 基本上它会警告你,某些东西可能不像你想象的那样。