Reputation: 4929
I have the following scenario...
Header file:
#define TRIG_INDEX 200
#define PATH(target_p) some.path.to.target##target_p
Source file:
read_from_target(PATH(TRIG_INDEX));
As the PATH
macro appends the target_p
to the text at the end, compilation fails as
some.path.to.targetTRIG_INDEX
is not a valid path.
I was expecting to get read_from_target(some.path.to.target200)
in the above scenario.
How can I (if at all) define the macros to accept such scenario?
Upvotes: 1
Views: 255
Reputation: 213408
The pre-processor macro expansion/replacement rules for function-like macros are rather intricate. Basically it does so in the following order:
The stuff after the macro name is known as the replacement list. In this case PATH_TARGET(target_p)
- things that PATH
should be replaced with.
The occurrence of ##
or #
together with a macro parameter means that the parameter gets replaced with its corresponding pre-processor token sequence (if applicable). In this case, the parameter target_p
gets replaced with TRIG_INDEX
, so we get some.path.to.target##TRIG_INDEX
creating the new pre-processor token some.path.to.targetTRIG_INDEX
, which is not as intended.
Other macro parameters get expanded. Doesn't apply here.
The replacement list is then rescanned for macro names to expand, but it's too late since pre-processor token concatenation with ##
has already occurred.
The part "other macro parameters get expanded" above is useful to fix the problem. So macro parameters in the replacement list take precedence over macro names. We can take advantage of this by adding a helper macro:
#define TRIG_INDEX 200
#define EXPAND(tgt) some.path.to.target##tgt
#define PATH(target_p) EXPAND(target_p)
Now in the expansion of the replacement list of PATH
, we first get macro parameter expansion: taget_p
is replaced and we get EXPAND(TRIG_INDEX)
. The replacement list is then rescanned for macro names to replace, the pre-processor finds two such macro names: EXPAND
and TRIG_INDEX
. Both are expanded and so TRIG_INDEX
is replaced with 200
. Then EXPAND
is expanded recursively according to the same rules (##
enforcing an expansion of that macro parameter tgt
into 200
before anything else).
For details, see the C17 standard chapter 6.10.3 - this chapter is also the one which specifies the behavior of the # and ## operators.
Upvotes: 3
Reputation: 41017
The argument must be expanded by the macro:
#define TRIG_INDEX 200
#define PATH_TARGET(x) some.path.to.target##x
#define PATH(target_p) PATH_TARGET(target_p)
Upvotes: 4