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

时间:2012-11-29 05:35:45

标签: c++ c gcc compiler-errors

Screen Shot of the Program with trigraphs compiled using Turbo C++

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

#include<stdio.h>

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

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

4 个答案:

答案 0 :(得分:10)

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

引用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编译器必须诊断任何违反语法规则或约束的行为,但它可以发出任意数量的附加警告 - 并且无需区分所需的诊断和其他警告。

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

事实上,很可能使用三元组意外比正确使用它们更多

~

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

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

答案 1 :(得分:5)

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

gcc -trigraphs ...

GCC 4.7.1手册说:

  

-trigraphs

     

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

它还说:

  

-Wtrigraphs

     

如果遇到任何可能改变其含义的三字母,则发出警告   程序(评论中的三字符不会被警告)。这个警告是   由-Wall启用。

答案 2 :(得分:2)

他们可能是turned off by default

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

GCC might be one of the latter。虽然它应该默认为ignore with warning,但在这种情况下,忽略可能会导致编译错误

答案 3 :(得分:1)

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

您看到的警告将帮助您快速发现可能的罪魁祸首来追踪错误的来源。基本上它是警告你可能不像你想象的那样。