14

The following C++ code compiles and works as the programmer intended on GCC (4.0.4)

#define FOO(x,y,z) ((x)*(y)*(z))
#define BAR(x) FOO(x,1)
#define BAZ 3,7

int main()
{
    return BAR(BAZ); /* interpreted as return ((3)*(7)*(1)); */
}

However, the macros cause an error on Microsoft Visual C++ Express 2010:

main.cpp(7): warning C4003: not enough actual parameters for macro 'FOO'
main.cpp(7): error C2059: syntax error : ')'

The issue seems to be that the Microsoft compiler, while handling the BAR macro internally, does not expand the BAZ macro to parameters that could be used as two separate parameters to macro FOO.

According to the standard, which compiler handles the situation correctly?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
otto
  • 1,138
  • 6
  • 14
  • Seems like what you're really looking for is [variadic macros](http://en.wikipedia.org/wiki/Variadic_macro). – leftaroundabout May 21 '12 at 11:17
  • 6
    @leftaroundabout it doesn't seem like he is... – Luchian Grigore May 21 '12 at 11:18
  • 3
    @iammilind: What's missing from chapter 16 of the standard? How is it not a 'real' standard? – CB Bailey May 21 '12 at 11:31
  • 1
    @iammilind Of course it does. It's designed to allow some leeway in the implementation, and certain operations involving token pasting result in undefined behavior, but that's not the case here. (Typically, in cases where there is undefined behavior, g++ will signal an error, where most other compilers will accept it.) – James Kanze May 21 '12 at 11:48
  • @CharlesBaily, you are right. Deleting comments (once login to PC). – iammilind May 23 '12 at 00:50
  • Is there a way to get/force the macros to be expanded inside out (e.g. with another layer of macros), so that BAZ in the example gets expanded first? I have a use-case where I need one name expanded into two (for each name in a list of names) for a set of macros and I don't want to repeat the pairs everywhere because that will be error prone. – intel_chris May 30 '19 at 09:15

1 Answers1

14

According to 16.3.4 of ISO/IEC 14882:2003 (C++ Stardard) macro expansion is performed as follows:

  1. Macro invocation is replaced with the macro's replacement list (the body) where each parameter name (unless it is affected by # or ##) is substituted with a complete macro expansion of corresponding argument specified in macro invocation.
  2. The result of step 1 is rescanned. If there are more macro invocations in it (except those already expanded getting the text under consideration), they are expanded according to the same procedure recursively.

The sequence of steps for the code you specified is:

  1. BAR(BAZ)
  2. FOO(3,7,1)
  3. ((3)*(7)*(1))

So GCC is right, and VC is not. But the error which VC complains about is that FOO has 3 arguments and BAR specifies only 2 of them. VC apparently tries to catch errors as soon as possible and goes a bit too far in it.

Alex Bakulin
  • 1,668
  • 11
  • 17
  • 1
    I don't understand how the algorithm that you have given corresponds to the GCC behaviour. If I read it correctly, the algorithm goes as follows: `BAR(BAZ)` is an invocation of `BAR` with the argument `BAZ`, so gets replaced with `FOO(BAZ,1)`. This now gets rescanned. The first macro that it finds is `FOO`, so now it attempts to expand `FOO` with the arguments `BAZ` and `1`. This is not enough arguments, so preprocessing fails. Why does rescanning `FOO(BAZ,1)` expand the `BAZ` first, when scanning `BAR(BAZ)` expanded the `BAR` first? – Mankarse May 24 '12 at 09:05
  • Thanks for the clear and complete explanation. I learnt a lot. – Mankarse May 24 '12 at 12:53