Protecting a comma in a C/C++ macro parameter

I just spent a couple of hours to find a way to "protect" commas in C/C++ preprocessor parameters. Consider the following example:

  1. #define ID(x) x
  2. //...
  3. printf("%s %s!\n", ID("hello", "world"));

This will not work. My compiler will say:

  1. c:\test.cpp(7) : warning C4002: too many actual parameters for macro 'ID'

The problem is that the comma between "hello" and "world" is interpreted as argument seperator of the ID macro (which makes the two being two arguments), although we want it to be part of one single argument. There's no way known to me to protect the comma (like protecting quotes with a backslash in C). Still, there's a workaround.

The solution

The trick is to define another macro which takes many parameters and concatenates them putting commas between them. This can be combined with variadic macros to be able to concatenate as many arguments as you want.

  1. #define CONCAT(...) __VA_ARGS__

The ellipsis takes as an arbitrary number of arguments, __VA_ARGS concatenates them using commas as seperators.

Now, the following will work.

  1. #define CONCAT(...) __VA_ARGS__
  2. #define ID(x) x
  3. //...
  4. printf("%s %s!\n", ID(CONCAT("hello", "world")) );

Conclusion

The lengthy search for that solution taught me another time not to use macros if you don't absolutely have to. Unfortunately, in my case, i had to. In case someone else has to as well, he may find that trick useful.

Comments

Or, you could do this...

  1. #define ID(x) x
  2. printf("%s %s!\n", ID(("hello", "world")) );

Notice the extra pair of parentheses.

Well, the result of ("hello",

Well, the result of ("hello", "world") is "world". I think the result is not what the author wanted. It compile, but it does not work...

Another way is to define a comma like this:

  1. #define KO ,

and use this within the makro call:
  1. printf("%s %s!\n", ID("hello" KO "world"));

easy

lol, that was easy.

Thanks! I did need this tip.

Hi Ingo-

Thanks for the writeup - I found it through the C++ forum* and I appreciate your having posted it to there.

-Charlie
*
http://cboard.cprogramming.com/cplusplus-programming/100211-warning-c400...

Thanks :)

Haha, they were funny: close the thread and take away any possibility for me to reply. I usually try to post an answer wherever I did NOT find it when I was looking for one... Whatever... Thanks for letting me know though :)

Only works on Microsoft compiler

I too ran up against that little trick. Unfortunately, it only works on the Microsoft compiler because of it's non-conformance to the C99 standard. I can't quote the location, but the standard says something to the effect that the __VA_ARGS__ shall be "tokenized" into the number of arguments.
The little CONCAT() macro you have depends on __VA_ARGS__ not being tokenized properly. Otherwise, it would have stripped out the intermediate commas. I've been racking my brain for several days on how to re-insert those darn commas for a portable solution. Thus far, I've only been successful on the Microsoft compiler. No luck with GNU. I've gotten a 99% solution, but GCC won't let me concatenate a comma back into my expression (I was trying to write a macro for a try{expresision}catch() block that gets used for a matrix class. Unfortunately, commas in the expression created major headaches for me.