给定之前已定义的宏:
#define FILENAME somefile.h
我想将此与另一个定义此文件(相对)路径的宏字符串连接起来。我目前的做法是这样做:
#define DIRECTORY ../somedir/
#define STRINGIFY_(x) #x
#define FILE2_(dir, file) STRINGIFY_(dir ## file)
#define FILE_(dir, file) FILE2_(dir, file)
#include FILE_(DIRECTORY, FILENAME)
然而,这会导致错误(GCC4.9):
错误:粘贴" /"和"文件"不提供有效的预处理令牌
从DIRECTORY
定义中删除最后的正斜杠会消除此错误,但显然不会产生所需的结果。当我试图以/
走私时,会出现类似的错误。例如:
#define FILE2_(dir, file) STRINGIFY_(dir ## / ## file)
出于同样的原因不起作用。
我想知道这里出了什么问题,显然,如何规避这个问题。
编辑:在Columbo的建议中将双下划线更改为单曲。显然,包含双下划线的标识符保留给实现,无论它们出现在何处(我的印象是,这仅适用于ID开头的双下划线)。
答案 0 :(得分:3)
[cpp.include] / 4:
表单
的预处理指令允许使用
# include
pp-tokens new-line(与前两种形式中的一种不匹配)。该 处理指令
<小时/> 152 请注意,相邻的字符串文字不是 连接成单个字符串文字(请参阅翻译阶段 在2.2);因此,导致两个字符串文字的扩展是一个 指令无效。include
后的预处理标记 就像在普通文本中一样(即,每个标识符当前定义为 宏名称被替换的预处理列表替换 令牌)。如果所有替换后产生的指令没有 匹配前两个表单中的一个,行为是 未定义。 152
因此虽然#include MACRO
有效,但MACRO
必须直接扩展为#include
的其他有效参数。字符串文字的串联在预处理后发生两个翻译阶段。
此外,在##
运算符的定义中,[cpp.concat] / 3:
对于类似对象和类似函数的宏调用,在重新检查替换列表之前需要更多 要替换的宏名称,替换列表中的
##
预处理标记的每个实例(不是来自 删除参数)并将前面的预处理标记与以下预处理连接起来 令牌即可。 [..] 如果结果不是有效的预处理令牌,则行为未定义。
因此A##B
的结果必须是一个有效的预处理令牌。 /是一个自己的预处理令牌,目录和文件的名称也是如此
您无法连接"abc
和/xyz"
,因为abc/
不是有效的预处理令牌 - "abc
不是一个预处理令牌,而是两个,但"abc"
是一个。
另一方面,如果您连接<abc/
和xyz>
,那么/
和xyz
会被连接,检查,我们又会遇到问题。
因此,似乎无法使用##
连接路径。你的方法对我来说也是不可能的。
<小时/> 有了海湾合作委员会,这很好,但是:
#define PATH <foo/bar/
#define FILE boo>
#define ARG PATH FILE
#include ARG
它works因为GCC预处理器删除了空格(出于某种原因)。不适用于VC ++或Clang,无论如何都不在标准范围内,所以绝对不推荐。