the problem about different treatment to __VA_ARGS__ when using VS 2008 and GCC

后端 未结 2 1919
长情又很酷
长情又很酷 2021-01-18 05:13

I am trying to identify a problem because of an unusual usage of variadic macros. Here is the hypothetic macro:

#define va(c, d, ...) c(d, __VA_ARGS__)
#defi         


        
相关标签:
2条回答
  • 2021-01-18 05:47

    There is an easy way to deal with this problem:

    #define exp(...) __VA_ARGS__
    #define va(c, d, ...) c(d, __VA_ARGS__)
    #define var(a, b, ...)  exp(va(__VA_ARGS__, a, b))
    
    var(2, 3, printf, “%d %d %d\n”, 1);
    

    This will do the trick on VS 2008 and it won't affect gcc

    0 讨论(0)
  • 2021-01-18 05:55

    Look into the ISO/IEC 9899:1999, chapter 6.10.3.1. It states that:

    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.

    So in va the first argument c has one preprocessing token being __VA_ARGS__, which, according to this paragraph, must be macro replaced before being substituted to c (which still does not give the answer as to which compiler is right)

    But later:

    An identifier __VA_ARGS__ that occurs in the replacement list shall be treated as if it were a parameter, and the variable arguments shall form the preprocessing tokens used to replace it.

    According to the first fragment, first the arguments to var are identified. They are: 2, 3, printf, “%d %d %d\n” and 1. Now argument substitution takes place. This means that parameters from var's replacement list are taken and replaced. However, the second fragment states, that identifier __VA_ARGS__ is to be treated as a parameter, so it must be substituted to printf, “%d %d %d\n”, 1. Now there are no macros inside parameters, so no further substitution takes place, resulting in the expansion of var(2, 3, printf, “%d %d %d\n”, 1); into va(printf, “%d %d %d\n”, 1, 2, 3);. Because va is a macro, it is also expanded, giving the result of printf(“%d %d %d\n”, 1, 2, 3);. Now if you take VS 2008's reasoning, how can it identify the arguments to va, if one of them is __VA_ARGS__ from var, and can contain many arguments? Well, it treats __VA_ARGS__ as an argument to va, which in my opition is wrong, as, according to fragment one, argument substitution takes place only after the arguments for invocation have been identified.

    So it seems to me, that in var the preprocessor has to first identify the arguments to the invocation of the macro va, and then start expanding va. And this means that probably gcc is right here.

    It is also shown in C preprocessor and concatenation how processing tokens are macro-replaced in order, until there are no identifiers which can be further expanded as macros, or the preprocessor spots a recursion and terminates expansion.

    0 讨论(0)
提交回复
热议问题