3

Consider the following code

#define COMB(F, ...) F(__VA_ARGS__)


#define ADD(X, Y) (X + Y)


int foo() {
    return COMB(ADD, 1, 2);
}

I have done some experiments on Godbolt. Microsoft VS v19.22 (with /E flag) fails at preprocessing the macro's. It gives the following error

int foo() {

    return (1, 2 + );

}

example.cpp

<source>(8): warning C4003: not enough arguments for function-like macro invocation 'ADD'

GCC (with -E flag) simply outputs as expected

int foo() {
    return (1 + 2);
}

I took a look at the C99 standard. But I am still not sure which compiler is doing it right?

I hope somebody can help me with clarifying this.

Yunus King
  • 1,141
  • 1
  • 11
  • 23
  • Does VC support variadic macros? – alk Dec 06 '19 at 11:55
  • 1
    It does: https://learn.microsoft.com/en-us/cpp/preprocessor/variadic-macros?view=vs-2019 – alk Dec 06 '19 at 11:59
  • "Microsoft VS fails" and "I took a look at the C99 standard" kind of sums up the problem. You shouldn't assume that VS 1) correctly follows C99 2) correctly follows any standard at all. – Lundin Dec 06 '19 at 12:01
  • I am not assuming VS is doing anything right. That is why I have posted my question. – Yunus King Dec 06 '19 at 12:08
  • Well the code works as expected on every other compiler (I just tried gcc, clang, icc and msvc). Draw your conclusions from there. – Lundin Dec 06 '19 at 12:09
  • 1
    Does this answer your question? [Why does this variadic argument count macro fail with VC++?](https://stackoverflow.com/questions/5530505/why-does-this-variadic-argument-count-macro-fail-with-vc) – S.S. Anne Dec 06 '19 at 12:28

2 Answers2

2

I think gcc is correct. Although C11 6.10.3/12 describes the invocation of COMB as having two arguments (ADD and 1,2), once COMB has been expanded the resulting token sequence is ADD ( 1 , 2 ), and 6.10.3.4/1 is clear that the result of the first replacement is rescanned as a preprocessing token sequence. An argument from a previous step that consisted of multiple tokens is not somehow glued into a single token for rescanning.

6.10.3.4/1:

After all parameters in the replacement list have been substituted and # and ## processing has taken place, all placemarker preprocessing tokens are removed. The resulting preprocessing token sequence is then rescanned, along with all subsequent preprocessing tokens of the source file, for more macro names to replace

M.M
  • 138,810
  • 21
  • 208
  • 365
  • Interesting do you know if this interpretation/derivation differs in C99? – Yunus King Dec 06 '19 at 12:18
  • @ArisKoning I think (don't quote me on this) that the text hasn't changed from C99 to C11. I'd have to go get the diff draft. though. – S.S. Anne Dec 06 '19 at 12:33
  • @ArisKoning C99 added the part about "and # and ## processing has taken place, all placemarker preprocessing tokens are removed". The stuff about placemarkers for ## is new in C99. What it means more precisely in practice, I don't know. – Lundin Dec 06 '19 at 14:20
  • @ArisKoning But then again MCVC struggled with C90 compliance to begin with. – Lundin Dec 06 '19 at 14:20
1

MSVC expands __VA_ARGS__ after passing it into the macro. You'll have to manually expand the macro like this:

#define EXPAND(x) x
#define COMB(F, ...) EXPAND(F(__VA_ARGS__))

#define ADD(X, Y) (X + Y)

GCC is the correct compiler in this case.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
  • Yup, this seems to be the workaround that I was searching for. VS does the rescan too soon, i.e. before the expansion of `__VA_ARGS__`. – Yunus King Dec 06 '19 at 12:55