4

From usbtiny/defs.h (AVR libc USB code for ATTiny controllers):

#define CAT2(a,b)               CAT2EXP(a, b)
#define CAT2EXP(a,b)            a ## b
#define CAT3(a,b,c)             CAT3EXP(a, b, c)
#define CAT3EXP(a,b,c)          a ## b ## c

What is the ## operator? I've been doing this for 30 years, and I'm stumped. And google isn't helping because I don't think they're indexing those chars.

nsayer
  • 16,925
  • 3
  • 33
  • 51

2 Answers2

9

The ## symbol in a macro definition represents concatenation.

So

#define concat(a,b) a ## b

will mean that

concat (pri, ntf) ("hello world\n");

post-processes to

printf("hello world\n");

Documentation here.

Similarly useful is the stringify operator (#), with which this should not be confused.

A test:

/* test with
 *    gcc -E test.c
 * having removed the #include lines for easier to read output
 */

#include <stdio.h>
#include <stdlib.h>

#define concat(a,b) a ## b

int
main (int argc, char **argv)
{
  concat (pri, ntf) ("Hello world\n");
  exit (0);
}

And why the extra level of indirection? As Deduplicator points out in the comments to his answer below, without that, it will concatenate the literal terms specified, rather than the macro substituted terms. A useful list of such pitfalls is here.

abligh
  • 24,573
  • 4
  • 47
  • 84
2

CAT2 and CAT3 are the macros which should be called, the other two are part of their internal working.

#define CAT2(a,b)               CAT2EXP(a, b)
#define CAT2EXP(a,b)            a ## b

So, what happens if you call CAT2?

Well, first CAT2 is replaced, which macro-expands the literal arguments:

CAT2(a_eval, b_eval)

Which is replaced by concatenating both arguments to make one token, by the ## token concatenation operator.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • @nsayer; Wasn't it? The extra indirection is important, even though you had not yet recognized it, and thus did not explicitly ask about it. – Deduplicator Oct 26 '14 at 18:12
  • I'd upvote this is you said *why* the extra level of indirection is important. I agree it is, as I've run into this one before, but I can't remember for the life of me why. – abligh Oct 26 '14 at 18:14
  • @abligh: Otherwise the literal arguments will be concatenated, not after possible macro-replacements. – Deduplicator Oct 26 '14 at 18:15
  • 1
    @abligh: Suppose you've said `#define N 3`, then `CAT2EXP(A,N)` would be `AN`, but `CAT2(A,N)` would be `A3`. (Or vice-versa, I'm not sure :) – Mike Dunlavey Oct 26 '14 at 18:17
  • @Deduplicator - yup, that's the one. Upvote duly delivered. – abligh Oct 26 '14 at 18:17