views:

1598

answers:

2

I am trying to write a code, where name of functions are dependent on the value of a certain macro variable. To be specific, I am trying to write a macro like this:

#define VARIABLE 3
#define NAME(fun) fun ## _ ## VARIABLE

int NAME(some_function)(int a);

Unfortunately, the macro NAME() turns that into

int some_function_VARIABLE(int a);

rather than

int some_function_3(int a);

so the this is clearly the wrong way to go about it. Fortunately, the number of different possible values for VARIABLE is small so I can simply do an #if VARIABLE == n and list all the cases separately, but I was wondering if there is a clever way to do it.

+8  A: 
#define VARIABLE 3
#define NAME2(fun,suffix) fun ## _ ## suffix
#define NAME1(fun,suffix) NAME2(fun,suffix)
#define NAME(fun) NAME1(fun,VARIABLE)

int NAME(some_function)(int a);

Honestly, you don't want to know why this works. If you know why it works, you'll become that guy at work who knows this sort of thing, and everyone will come ask you questions. =)

Edit: if you actually want to know why it works, I'll happily post an explanation, assuming no one beats me to it.

Stephen Canon
Could you explain why it needs two levels of indirection. I had an answer with one level of redirection but I deleted the answer because I had to install C++ into my Visual Studio and then it wouldn't work.
Cade Roux
See Jonathan Leffler's most excellent explanation.
Stephen Canon
+22  A: 
$ cat xx.c
#define VARIABLE 3
#define PASTER(x,y) x ## _ ## y
#define EVALUATOR(x,y)  PASTER(x,y)
#define NAME(fun) EVALUATOR(fun, VARIABLE)

extern void NAME(mine)(char *x);
$ gcc -E xx.c
# 1 "xx.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "xx.c"





extern void mine_3(char *x);
$


Cade Roux asked why this needs two levels of indirection. The flippant answer is because that's how the standard requires it to work; you tend to find you need the equivalent trick with the stringizing operator too.

Section 6.10.3 of the C99 standard covers 'macro replacement', and 6.10.3.1 covers 'argument substitution'.

After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.

In the invocation NAME(mine), the argument is 'mine'; it is fully expanded to 'mine'; it is then substituted into the replacement string:

EVALUATOR(mine, VARIABLE)

Now the macro EVALUATOR is discovered, and the arguments are isolated as 'mine' and 'VARIABLE'; the latter is then fully expanded to '3', and substituted into the replacement string:

PASTER(mine, 3)

The operation of this is covered by other rules (6.10.3.3 'The ## operator'):

If, in the replacement list of a function-like macro, a parameter is immediately preceded or followed by a ## preprocessing token, the parameter is replaced by the corresponding argument’s preprocessing token sequence; [...]

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.

So, the replacement list contains x followed by ## and also ## followed by y; so we have:

mine ## _ ## 3

and eliminating the ## tokens and concatenating the tokens on either side combines 'mine' with '_' and '3' to yield:

mine_3

This is the desired result.


If we look at the original question, the code was (adapted to use 'mine' instead of 'some_function'):

#define VARIABLE 3
#define NAME(fun) fun ## _ ## VARIABLE

NAME(mine)

The argument to NAME is clearly 'mine' and that is fully expanded.
Following the rules of 6.10.3.3, we find:

mine ## _ ## VARIABLE

which, when the ## operators are eliminated, maps to:

mine_VARIABLE

exactly as reported in the question.

Jonathan Leffler
+1 for descriptive macro names.
Stephen Canon
Yep, this solves the problem. I knew the trick with two levels of recursion -- I had to play with stringification at least once -- but didn't know how to do this one.
JJ