【问题标题】:#include file derived from macro __FILE__?#include 来自宏 __FILE__ 的文件?
【发布时间】:2012-11-09 05:28:07
【问题描述】:

观察以下程序:

#include __FILE__
main(){}

预处理器陷入无限递归,包括自身内部的副本并抱怨 main() 已被定义。


如果我可以使用宏来包含文件, 我可以根据__FILE__ 导出文件名并包含它吗?


例如,我想在 "foo.cpp" 中包含 "foo.h",但从 __FILE__ 派生它。

可以用预处理器完成吗?

【问题讨论】:

  • 不能编辑文件名,相邻字符串文字的拼接发生在翻译的第6阶段,但是预处理发生在第4阶段,所以不能使用字符串拼接。这意味着不可能从__FILE__ 构建一个可以被预处理器包含的文件名。

标签: c++ macros include c-preprocessor


【解决方案1】:

C 标准规定了#include 的三种形式:

#include <file>
#include "file"
#include ANYTHING ELSE

在前两种情况下,不会发生宏扩展,因此无法改变行为。在第三种情况下,C99 说(§6.10.2p4):

指令中#include 之后的预处理标记是[宏扩展]。所有替换后产生的指令应匹配前两种形式之一[脚注:请注意,相邻的字符串文字不会连接成单个字符串文字]。将 预处理标记对或一对 " 字符之间的一系列预处理标记组合成单个标头名称预处理标记的方法是实现定义的。

C++98 §16.2p4 中出现的措辞略有不同,但实际上等效。

任何带有“shall”的句子都提出了一个硬性要求:在这种情况下,如果ANYTHING ELSE 扩展为除了以&lt; 开头并以&gt; 结尾的标记序列之外的任何内容,则程序是非良构的,或以" 开头和结尾。该标记序列的确切解释是实现定义的,但请注意脚注明确禁止字符串文字连接。

因此,由于__FILE__ 的扩展是一个字符串常量,在#include 中使用它的唯一方法是

#include __FILE__

正如您所发现的,这会导致无限递归,并且

#define LT <
#define GT >
#include LT __FILE__ etc GT

这对我可以方便地测试的所有编译器都有有趣但无用的影响。假设上面是在一个名为test.c的文件中:

  • GCC 尝试打开一个名为 "test.c" etc 的文件,其中包含引号和空格。
  • clang 更加字面化,它查找相同的文件名,但带有前导和尾随空格。
  • MSVC 宏扩展LT(我认为这是违反一致性的),抱怨没有匹配的&gt;,然后尝试打开一个文件命名为__FILE__ etc GT

GCC's behavior is documented here;其他任何事情你都靠自己。)

tl;dr:没有办法从预处理器内部做你想做的事。我建议从构建系统中计算出要包含的文件的名称,并使用 -D 开关通知编译器(在 Unixy 系统上,您需要双引号,-DINCLUDEME='"includeme.h"';我不需要说CMD)

【讨论】:

    【解决方案2】:

    我想出的最好的是:

    #define foo(x) #x
    #include foo(x)
    

    prog.cpp:2:16: 错误: x: 没有这样的文件或目录

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-21
      • 1970-01-01
      • 2011-07-01
      • 2014-03-10
      • 2010-12-14
      • 2014-09-04
      相关资源
      最近更新 更多