5

Consider the following macro:

#define CAT(X, Y) X ## Y
#define CMB(A, B) CAT(A, B)
#define SLB_LOGGING_ALGORITHM CMB(Logging, SLB_ALGORITHM)

where SLB_ALGORITHM is a defined pre-processor symbol.

If I just use CAT directly instead of CMB, SLB_ALGORITHM does not get expanded. Why is that the case and how exactly does the indirection help?

AlwaysLearning
  • 7,257
  • 4
  • 33
  • 68

2 Answers2

5

## is a string concatenator, so if you call CAT(Logging, SLB_ALGORITHM) from SLB_LOGGING_ALGORITHM macro, this will result in concatenation of string Logging with string SLB_ALGORITHM, that is: LoggingSLB_ALGORITHM which is likely not what you want.

When calling CMB(Logging, SLB_ALGORITHM) from SLB_LOGGING_ALGORITHM macro, instead, preprocessor first expands Logging and SLB_ALGORITHM (call to CMB()) then concatenate the expanded strings (call to CAT()).

shrike
  • 4,449
  • 2
  • 22
  • 38
2

To quote this answer:

When you have a macro replacement, the preprocessor will only expand the macros recursively if neither the stringizing operator # nor the token-pasting operator ## are applied to it.

So the preprocessor does not expand a given macro when ## is applied to it. This is why it is exapnded in the CMB(A, B) level but not when directly using CAT(X, Y) .

Community
  • 1
  • 1
Tomer
  • 3,149
  • 23
  • 26
  • I still don't get how this works exactly. When `CAT` is used directly, the first substitution should produce `CAT(Logging, SLB_ALGORITHM)`, which does not have `##` either... – AlwaysLearning May 08 '16 at 18:42
  • When `CAT(Logging, SLB_ALGORITHM)` is used directly `SLB_ALGORITHM` is passed only once to a macro so it translates to `Logging ## SLB_ALGORITHM` which does contain `##`. – Tomer May 08 '16 at 19:50