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):
error: pasting "/" and "file" does not give a valid preprocessing token
Removing the final forward slash from the DIRECTORY
definition removes this error, but obviously does not yield the desired result. 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. 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).
[cpp.include]/4:
A preprocessing directive of the form
# include
pp-tokens new-line(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 (i.e., each identifier currently defined as a macro name is replaced by its replacement list of preprocessing tokens). If the directive resulting after all replacements does not match one of the two previous forms, the behavior is undefined.152
152Note that adjacent string literals are not concatenated into a single string literal (see the translation phases in 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
. The concatenation of string literals happens two translation phases after preprocessing.
Also, in the definition of the ##
operator, [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. / 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.
On the other hand, if you concatenate <abc/
and xyz>
, then /
and xyz
are concatenated, examined, and we have a problem again.
Thus it appears to be impossible to concat the paths using ##
. Your approach looks quite impossible to me, too.
#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). Does not work on VC++ or Clang and isn't covered by standard anyway, so definitely not recommended.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With