观察下面的程序:
#include __FILE__
main(){}
预处理器陷入无限递归,包括自身内部的拷贝,并提示 main()
已经被定义。
如果我可以使用宏来包含文件,
我可以根据 __FILE__
导出文件名并包含它吗?
例如,我想在 "foo.cpp"
中包含 "foo.h"
,但它是从 __FILE__
.
可以用预处理器来完成吗?
最佳答案
C 标准指定了三种形式的 #include
:
#include <file>
#include "file"
#include ANYTHING ELSE
在前两种情况下,没有发生宏扩展,因此无法改变行为。在第三种情况下,C99 说 (§6.10.2p4):
The preprocessing tokens after
#include
in the directive are [macro-expanded]. The directive resulting after all replacements shall match one of the two previous forms [footnote: Note that adjacent string literals are not concatenated into a single string literal]. The method by which a sequence of preprocessing tokens between a < and a > preprocessing token pair or a pair of " characters is combined into a single header name preprocessing token is implementation-defined.
C++98 §16.2p4 中的措辞略有不同,但实际上是等效的。
任何带有“shall”的句子都提出了一个硬性要求:在这种情况下,如果 ANYTHING ELSE
则程序格式错误扩展为除以 <
开头的标记序列之外的任何内容并以 >
结尾, 或以 "
开头和结尾.该标记序列的确切解释是实现定义的,但请注意脚注明确禁止字符串文字连接。
因此,作为 __FILE__
的扩展是一个字符串常量,在 #include
中使用它的唯一方法是
#include __FILE__
如您所见,这会导致无限递归,并且
#define LT <
#define GT >
#include LT __FILE__ etc GT
它对我可以方便地测试的所有编译器都有有趣但无用的影响。假设以上内容在名为 test.c
的文件中:
- GCC 尝试打开名为
"test.c" etc
的文件, 逐字包含引号和空格。 - clang 更符合字面意思,它会查找相同的文件名,但前导空格和尾随空格。
- MSVC 宏扩展仅
LT
(我认为这是违反一致性的意见),提示没有匹配>
, 然后尝试打开名为__FILE__ etc GT
的文件.
( GCC's behavior is documented here ; 其他任何事都靠你自己。)
tl;dr:没有办法从预处理器内部做你想做的事。我建议从您的构建系统中计算出要包含的文件的名称,并使用 -D
将其通知编译器。开关(在 Unixy 系统上你需要双引号,-DINCLUDEME='"includeme.h"'
;我不会说 CMD)
关于c++ - #include 文件派生自宏 __FILE__?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13485192/