GCC实施的尖括号包含。为什么必须如下所述?


10

本文档在其2.6计算的包括部分中具有以下段落:

如果该行扩展到以<令牌开头并包括>令牌的令牌流,则<和第一个>之间的令牌将合并以形成要包含的文件名。令牌之间的任何空格都减少为一个空格;那么将保留初始<之后的任何空格,但忽略闭合>之前的结尾空格。CPP根据尖括号包含的规则搜索文件。

我知道这是实现定义的,但是为什么GCC必须采用这种方式?我指的是上面突出显示的句子。

编辑

我刚刚注意到,上面引用的第三段之前的内容如下:

定义宏时必须小心。#define保存令牌,而不是文本。预处理器无法知道该宏将用作的参数#include,因此它会生成普通标记,而不是标头名称。如果您使用的双引号包含与字符串常量足够接近,则这不太可能引起问题。 但是,如果使用尖括号,则可能会遇到麻烦

有谁知道这里指出了什么麻烦?


6
最好的猜测是,GCC的开发人员认为,文件名末尾有空格是可憎的。
user3386109

1
带有前导和/或尾随空格的文件名非常挑剔,尤其是在Windows上。
雷米·勒博

1
仅仅因为已经定义了它,并不一定意味着必须这样定义。该标准未强制要求。
eerorika

Visual Studio会删除初始空间和结束空间,因此行为会有所不同。HP aCC的行为类似于gcc(可能出于兼容性原因)。
Slimak

有时,文档只是描述了代码发生的事情,而不是相反的情况,特别是在无关紧要的情况下(如果使用双引号,则可以在任何地方使用任何空间)。
rustyx

Answers:


8

我想实现者在实现此功能时选择了最简单的方法,而没有考虑太多。

最初的实施似乎在2000-07-03进行了探索(两年前!)。相关部分看起来像(source):

  for (;;)
    {
      t = cpp_get_token (pfile);
      if (t->type == CPP_GREATER || t->type == CPP_EOF)
        break;

      CPP_RESERVE (pfile, TOKEN_LEN (t));
      if (t->flags & PREV_WHITE)
        CPP_PUTC_Q (pfile, ' ');
      pfile->limit = spell_token (pfile, t, pfile->limit);
    }

值得注意的是,它会在为CPP_GREATER令牌保留内存之前看到令牌(即>)时中断。这是有道理的,因为当令牌不会被写入缓冲区时,无需分配内存。

然后,仅保留内存之后,预处理器才检查令牌是否具有前面的空格(t->flags & PREV_WHITE),并且当令牌存在时,将空白字符写入缓冲区。

其结果是,在< foo / bar >只有前空格foo(即,后的初始<),/bar被保持。


很棒,很好的答案。这是我第一次有机会在GCC中看到一段代码。这次真是万分感谢。
Ayrosa

但是条件是否if (t->flags & PREV_WHITE) CPP_PUTC_Q (pfile, ' ');与文档中所说的相矛盾:“令牌之间的任何空格都减少到一个空格; ...”吗?
Ayrosa
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.