5

I was reading a book on C programming language where I found:

#define cat(x,y) x##y
#define xcat(x,y) cat(x,y)

calling cat(cat(1,2),3) produces error whereas calling xcat(xcat(1,2),3) produces expected result 123.

How are both working differently ?

a3f
  • 8,517
  • 1
  • 41
  • 46
shakim
  • 186
  • 1
  • 7
  • possible duplicate of [Why do i need double layer of indirection for macros?](http://stackoverflow.com/questions/8231966/why-do-i-need-double-layer-of-indirection-for-macros) – anatolyg Mar 30 '15 at 11:49

1 Answers1

5

Macros whose replacement lists depends on ## usually can't be called in nested fashion.
cat(cat(1,2),3) is not expanded in a normal fashion, with cat(1,2) yielding 12 and then cat(12, 3) yielding 123.
Macro parameters that are preceded or followed by ## in a replacement list aren't expanded at the time of substitution.

6.10.3.1 Argument substitution

1 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.

As a result, cat(cat(1,2),3) expands to cat(1,2)3, which can't be expanded further, because there is no macro named cat(1,2)3.

In case

#define xcat(x,y) cat(x,y)  

writing xcat(xcat(1,2),3) will work. As the preprocessor expands the outer call of xcat, it will expand xcat(1,2) as well; the difference is that xcat's replacement list does not contain ## anymore.

xcat(xcat(1,2),3) ==> cat(12, 3) ==> 12##3 ==> 123
haccks
  • 104,019
  • 25
  • 176
  • 264
  • This answer would be better if it were more explicit about how xcat works. But the question is a duplicate and there are excellent answers to the original. – rici Jun 21 '14 at 12:50
  • @rici; I read the answers in the provided link, but none of them answered about the working both o `#define`. – haccks Jun 21 '14 at 13:11
  • 1
    I had always wondered why you needed such convoluted macros to do things like make the version string in APR... this makes sense... I hadn't ever bothered to learn why, just copied the form of something that already worked (engineers do that right ;) – Grady Player Jun 21 '14 at 13:30
  • 1
    Should the word "deference" be "difference"? SO won't let me make that change because the edit is less than 6 characters... – hft Jun 21 '14 at 21:56
  • 2
    @haccks: You have to read 6.10.3.1 in conjunction with 6.10.3.3. `cat(cat(1,2),3)` is first replaced with `cat(1,2) ## 3` (the parameters are replaced literally, rather than with macro expansion). Then `##` attempts to concatenate `)` with `3`. However, `)3` is not a valid preprocessing token, so that's UB by 6.10.3.3/3 (8th line). I reread the linked question and also the question unearthed by Jayesh, and I think Chris Dodd's answer comes closest, but your answer is getting there :) – rici Jun 21 '14 at 22:40
  • @rici; Thanks for the quote and letting me know about the behavior :) – haccks Jun 21 '14 at 22:58