【问题标题】:Why does GCC emit a warning when using trigraphs, but not when using digraphs?为什么 GCC 在使用 trigraphs 时会发出警告,但在使用 digraphs 时不会发出警告?
【发布时间】:2015-05-11 11:58:39
【问题描述】:

代码:

#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!"); %>

不会引发任何警告。

那么,为什么编译器在使用三合字母时会警告我,而在使用二合字母时却没有?

【问题讨论】:

  • @ShafikYaghmour 我认为那里的答案包含可以在回答这个问题时给出的所有信息,即使 gcc 的新版本(或不同的前端?)将其对三元组的处理降级为警告。
  • @ShafikYaghmour 链接的问题仍然说 gcc 生成 warnings 并且错误来自 Turbo C。所以我认为从那以后没有任何改变。
  • @BlueMoon 我刚刚意识到行为看起来不同的原因是现在几乎每个人都在使用-std=xxx,这意味着gcc 将自动打开三元组。所以也许我同意这是重复的。
  • 三合字母和二合字母来自许多/大多数键盘没有适当按键的日子。今天,所有这些都已过时且不应使用。

标签: c gcc compiler-warnings digraphs trigraphs


【解决方案1】:

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

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

将此与二合字母进行对比,二合字母是新的标记,不会导致无声的变化。

【讨论】:

    【解决方案2】:

    gcc document on pre-processing 给出了一个很好的警告理由(强调我的):

    Trigraphs 并不流行,许多编译器都错误地实现了它们。可移植代码不应依赖于被转换或忽略的三元组。使用 -Wtrigraphs 时,GCC 会在 如果三元组被转换后可能会改变程序的含义时向您发出警告。

    在这个 gcc 文档中on Tokenization 解释了二合字母不像三合字母没有潜在的负面影响(强调我的):

    还有六个二合字母,C++ 标准将它们称为替代标记,它们只是拼写其他标点符号的替代方式。这是解决过时系统中缺少标点符号的第二次尝试。 它没有负面的副作用,不像三元组

    【讨论】:

    • 这不能回答为什么二合字母会发出警告(或者暗示它们更受欢迎)
    • @schnaader 这就是暗示,但我添加了另一个文档来明确说明
    • 所有三个答案都说明了同样的事情,但我喜欢你的答案,因为它包含简短、正确的引号。滴答声向你走去! :)
    【解决方案3】:

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

    标点符号是对 C 和 C++ 有意义的所有常用标点符号。 ASCII 中除了三个标点字符之外的所有标点字符都是 C 标点符号。例外是“@”、“$”和“`”。此外,所有两个和三个字符的运算符都是标点符号。还有六个二合字母,C++ 标准称之为替代标记,它们只是拼写其他标点符号的替代方式。这是解决过时系统中缺少标点符号的第二次尝试。与三元组不同,它没有负面影响,但覆盖范围不广。有向图及其对应的正常标点符号是:

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

    【讨论】:

      【解决方案4】:

      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
      

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

      相比之下,有向图相对良性,因为除了一些可能涉及宏的奇怪极端情况之外,在没有此类处理的情况下,任何包含可处理有向图的代码都不会具有合法意义。

      【讨论】:

        猜你喜欢
        • 2018-08-24
        • 2018-01-26
        • 1970-01-01
        • 1970-01-01
        • 2023-04-08
        • 1970-01-01
        • 1970-01-01
        • 2021-12-27
        • 2014-06-11
        相关资源
        最近更新 更多