The ##
operator concatenates two preprocessing tokens and must yield a single valid token. For example, from section 6.10.3.3 of the C99 spec:
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. Placemarker preprocessing tokens are handled specially: concatenation of two placemarkers results in a single placemarker preprocessing token, and concatenation of a placemarker with a non-placemarker preprocessing token results in the non-placemarker preprocessing token. If the result is not a valid preprocessing token, the behavior is undefined. The resulting token is available for further macro replacement. The order of evaluation of##
operators is unspecified.
So the expansion ExtBAR(name) ## _dud
is invalid since it would yield ExtBAR(object)_dud
.
I'd go with the following approach:
#ifdef FOO
# define ValFOO _foo
#else
# define ValFOO
#endif
#ifdef BAR
# define ValBAR _bar
#else
# define ValBAR
#endif
#ifdef DUD
# define ValDUD _dud
#else
# define ValDUD
#endif
#define CONCAT(a, b, c, d) a ## b ## c ## d
#define XCONCAT(a, b, c, d) CONCAT(a, b, c, d)
#define EXTEND(name) XCONCAT(name, ValFOO, ValBAR, ValDUD)
The intermediate XCONCAT
step is needed because macro arguments are not expanded if they're concatenated using ##
.