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.