简体   繁体   English

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

[英]C preprocessor: building a path string

Given a macro that has been defined previously: 给定一个先前已定义的宏:

#define FILENAME somefile.h

I want to concatenate this with another macro-string that defines the (relative) path of this file. 我想将此与另一个定义此文件(相对)路径的宏字符串连接起来。 My current approach is to do this like so: 我目前的做法是这样做:

#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)

This however results in an error (GCC4.9): 然而,这会导致错误(GCC4.9):

error: pasting "/" and "file" does not give a valid preprocessing token 错误:粘贴“/”和“file”不会提供有效的预处理令牌

Removing the final forward slash from the DIRECTORY definition removes this error, but obviously does not yield the desired result. DIRECTORY定义中删除最后的正斜杠会消除此错误,但显然不会产生所需的结果。 Similar errors appear when I try to smuggle the / in otherwise. 当我试图以其他方式走私/ ,会出现类似的错误。 For example: 例如:

#define FILE2_(dir, file) STRINGIFY_(dir ## / ## file)

does not work for the same reason. 由于同样的原因不起作用。

I would like to know what is going wrong here and, obviously, how to circumvent this. 我想知道这里出了什么问题,显然,如何规避这个问题。

EDIT : Changed double underscores to singles on Columbo's advice. 编辑 :在Columbo的建议下改变双重下划线为单曲。 Apparently, identifiers containing double underscores are reserved to the implementation, regardless of where they appear (I was under the impression that this only held true for double underscores at the beginning of an ID). 显然,包含双下划线的标识符保留给实现,无论它们出现在何处(我的印象是,这仅适用于ID开头的双下划线)。

[cpp.include]/4: [cpp.include] / 4:

A preprocessing directive of the form 表单的预处理指令

# include pp-tokens new-line # include PP-令牌新线

(that does not match one of the two previous forms) is permitted. (允许与前两种形式中的一种不匹配)。 The preprocessing tokens after include in the directive are processed just as in normal text (ie, each identifier currently defined as a macro name is replaced by its replacement list of preprocessing tokens). 在指令中include之后的预处理标记被处理,就像在普通文本中一样(即,当前定义为宏名称的每个标识符被其预处理标记的替换列表替换)。 If the directive resulting after all replacements does not match one of the two previous forms, the behavior is undefined. 如果在所有替换之后生成的指令与前两个表单中的一个不匹配,则行为未定义。 152 152


152 Note that adjacent string literals are not concatenated into a single string literal (see the translation phases in 2.2); 152 请注意,相邻的字符串文字不会连接成单个字符串文字(请参阅2.2中的翻译阶段); thus, an expansion that results in two string literals is an invalid directive. 因此,导致两个字符串文字的扩展是无效的指令。

So though #include MACRO is valid, MACRO must directly expand to an otherwise valid argument to #include . 因此虽然#include MACRO有效,但MACRO必须直接扩展为#include的其他有效参数。 The concatenation of string literals happens two translation phases after preprocessing. 字符串文字的串联在预处理之后发生两个翻译阶段。

Also, in the definition of the ## operator, [cpp.concat]/3: 另外,在##运算符的定义中,[cpp.concat] / 3:

For both object-like and function-like macro invocations, before the replacement list is reexamined for more macro names to replace, each instance of a ## preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing token . 对于类似对象和类似函数的宏调用,在重新检查替换列表以替换更多宏名称之前,替换列表中的##预处理标记的每个实例(不是来自参数)都将被删除, 并且前面的预处理标记与以下预处理标记连接 [..] If the result is not a valid preprocessing token, the behavior is undefined. [..] 如果结果不是有效的预处理标记,则行为未定义。

Hence the result of A##B must be one valid preprocessing token. 因此, A##B的结果必须是一个有效的预处理标记。 / is an own preprocessing token, and so are the names of the directories and files. /是一个自己的预处理令牌,目录和文件的名称也是如此。
You can't concatenate "abc and /xyz" , since abc/ is not a valid preprocessing token - "abc is not one preprocessing token, but two, though "abc" is one. 你不能连接"abc/xyz" ,因为abc/不是一个有效的预处理令牌 - "abc不是一个预处理令牌,而是两个,虽然"abc"是一个。
On the other hand, if you concatenate <abc/ and xyz> , then / and xyz are concatenated, examined, and we have a problem again. 另一方面,如果你连接<abc/xyz> ,那么/xyz被连接,检查,我们再次遇到问题。

Thus it appears to be impossible to concat the paths using ## . 因此,似乎不可能使用##路径。 Your approach looks quite impossible to me, too. 你的方法对我来说也是不可能的。


With GCC, this is fine though: 有了海湾合作委员会,这很好:

 #define PATH <foo/bar/ #define FILE boo> #define ARG PATH FILE #include ARG 

It works because GCCs preprocessor removes the white space (for some reason). 它的工作原理是因为GCC预处理器会删除空白区域(出于某种原因)。 Does not work on VC++ or Clang and isn't covered by standard anyway, so definitely not recommended. 不适用于VC ++或Clang,并且不受标准的约束,所以绝对不推荐。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM