C预处理器:构建路径字符串

时间:2015-04-13 09:18:29

标签: c macros include c-preprocessor

给定之前已定义的宏:

#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开头的双下划线)。

1 个答案:

答案 0 :(得分:3)

[cpp.include] / 4:

  

表单

的预处理指令      

# include pp-tokens new-line

     允许使用

(与前两种形式中的一种不匹配)。该   处理指令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

works因为GCC预处理器删除了空格(出于某种原因)。不适用于VC ++或Clang,无论如何都不在标准范围内,所以绝对不推荐。