为什么GCC在使用三字符时会发出警告,但在使用有向图时则不会?

时间:2015-05-11 11:58:39

标签: c gcc compiler-warnings digraphs trigraphs

代码:

#include <stdio.h>

int main(void)
{
  ??< puts("Hello Folks!"); ??>
}

上述程序在使用GCC 4.8.1与-Wall-std=c11进行编译时,会发出以下警告:

source_file.c: In function ‘main’:
source_file.c:8:5: warning: trigraph ??< converted to { [-Wtrigraphs]
     ??< puts("Hello Folks!"); ??>
 ^
source_file.c:8:30: warning: trigraph ??> converted to } [-Wtrigraphs]

但是当我将main的正文更改为:

<% puts("Hello Folks!"); %>

没有警告。

那么,为什么编译器在使用三字符时会发出警告,但在使用有向图时则不会?

4 个答案:

答案 0 :(得分:5)

gcc document on pre-processing为警告提供了相当好的理由(强调我的):

  

Trigraphs不受欢迎,许多编译器都不正确地实现它们。可移植代码不应该依赖于转换或忽略的三字母。使用-Wtrigraphs时GCC会在三字符可能会改变程序的含义(如果已转换)时向您发出警告。

并且在这个gcc文档中on Tokenization解释了不同于三字母的有向图不会产生潜在的负面影响(强调我的):

  

还有六个有向图,C ++标准称之为替代令牌,这只是拼写其他标点符号的替代方法。这是第二次尝试解决过时系统中缺少标点符号的问题。 没有负面影响,不像三字母

答案 1 :(得分:5)

因为三元组具有静默更改代码的不良影响。这意味着相同的源文件在有和没有三角形替换的情况下都有效,但会导致不同的代码。这在字符串文字方面尤其成问题,例如"<em>What??</em>"

语言设计和语言演变应努力避免无声的变化。让编译器警告三字符是一件好事。

将此与有效图形对比,后者是新标记,不会导致无声变化。

答案 2 :(得分:3)

可能是因为它没有负面影响,不像gcc文档中所述的三字母:

  

标点符号是标点符号的常用内容,对C和C ++有意义。 ASCII中的三个标点符号除了三个标点符号外都是C标点符号。例外是'@','$'和'`'。此外,所有两个和三个字符的运算符都是标点符号。还有六个有向图,C ++标准称之为替代令牌,它们只是拼写其他标点符号的替代方法。这是第二次尝试解决过时系统中缺少标点符号的问题。与三字母不同,它没有负面的副作用,但没有覆盖那么多的地面。有向图和它们相应的正常标点符号是:

 Digraph:        <%  %>  <:  :>  %:  %:%:
 Punctuator:      {   }   [   ]   #    ##

答案 3 :(得分:2)

Trigraphs很讨厌,因为它们使用的字符序列可以合法地出现在有效的代码中。用于在经典Macintosh代码上导致编译器错误的常见情况:

unsigned int signature = '????';  /* Should be value 0x3F3F3F3F */

Trigraph处理将把它变成:

unsigned int signature = '??^;  /* Should be value 0x3F3F3F3F */

当然不会编译。在一些稍微少见的情况下,这种处理有可能产生可编译的代码,但具有与预期不同的含义,例如

char *template = "????/1234";

会变成

char *template = "??S4"; // ??/ becomes \, and \123 becomes S

不是有意的字符串文字,但仍然完全合法。

相比之下,有向图是相对良性的,因为除了涉及宏的一些可能奇怪的角落情况之外,没有包含可处理有向图的代码在没有这种处理的情况下将具有合法含义。