Jor*_*eit 5 c macros include c-preprocessor
给定一个先前定义的宏:
#define FILENAME somefile.h
Run Code Online (Sandbox Code Playgroud)
我想将它与另一个宏字符串连接起来,该宏字符串定义此文件的(相对)路径。我当前的方法是这样做的:
#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)
Run Code Online (Sandbox Code Playgroud)
但是,这会导致错误(GCC4.9):
错误:粘贴“ /”和“文件”没有给出有效的预处理令牌
从DIRECTORY定义中删除最后的正斜杠可消除此错误,但显然不会产生所需的结果。当我尝试以/其他方式走私时,也会出现类似的错误。例如:
#define FILE2_(dir, file) STRINGIFY_(dir ## / ## file)
Run Code Online (Sandbox Code Playgroud)
由于相同的原因而无法正常工作。
我想知道这里出了什么问题,显然是如何避免这一点。
编辑:在哥伦布的建议下,将双下划线改为单打。显然,包含双下划线的标识符将保留给实现,而不管它们出现在什么地方(我的印象是,仅对ID开头的双下划线成立)。
[cpp.include]/4:
表单的预处理指令
# includepp-代币换行(与前面两种形式之一不匹配)是允许的。
include指令中后面的预处理标记的处理方式与普通文本中一样(即,当前定义为宏名称的每个标识符都被替换为预处理标记的替换列表)。如果所有替换后生成的指令与前面的两种形式之一不匹配,则行为未定义。152
152 请注意,相邻的字符串文字不会连接成单个字符串文字(参见 2.2 中的翻译阶段);因此,导致两个字符串文字的扩展是无效的指令。
因此,虽然#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
Run Code Online (Sandbox Code Playgroud)
它之所以有效,是因为 GCC 预处理器删除了空白(出于某种原因)。不适用于 VC++ 或 Clang,并且不属于标准范围,因此绝对不推荐。