Home > Backend Development > C++ > body text

Why Does Variadic Macro Expansion Differ Between MSVC and GCC?

Patricia Arquette
Release: 2024-11-05 08:36:02
Original
930 people have browsed it

Why Does Variadic Macro Expansion Differ Between MSVC   and GCC?

Variadic Macro Expansion in MSVC

The variadic macro mechanism in MSVC behaves differently from the one in GCC, leading to difficulties in expanding macros with multiple arguments. Consider the following macros:

<code class="cpp">#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1)

#define FULLY_EXPANDED(count, ...) \
  MAC ## count (__VA_ARGS__)

#define SEMI_EXPANDED(count, ...) FULLY_EXPANDED(count, __VA_ARGS__)

#define EXPAND_THESE(...) SEMI_EXPANDED(VA_NARGS(__VA_ARGS__), __VA_ARGS__)

#define ACTUAL_MACRO(x) parent->GetProperty<x>();
#define MAC1(a) ACTUAL_MACRO(a)
#define MAC2(a,b) MAC1(a) ACTUAL_MACRO(b)
#define MAC3(a,b,c) MAC2(a,b) ACTUAL_MACRO(c)
#define MAC4(a,b,c,d) MAC3(a,b,c) ACTUAL_MACRO(d)
#define MAC5(a,b,c,d,e) MAC4(a,b,c,d) ACTUAL_MACRO(e)</code>
Copy after login

In GCC, this macro would expand to:

<code class="cpp">struct MyStructure
{
  void Foo()
  {
    parent->GetProperty<Property1>(); 
    parent->GetProperty<Property2>(); 
    parent->GetProperty<Property3>(); 
    parent->GetProperty<Property4>();
  }

  Base * parent;
}</code>
Copy after login

However, in MSVC , it expands to:

<code class="cpp">struct MyStructure
{
  void Foo()
  {
    parent->GetProperty<Property1, Property2, Property3, Property4>();
  }

  Base * parent;
}</code>
Copy after login

Explanation

The issue arises because MSVC applies macro expansion level-by-level, while GCC expands macros fully in one pass. Consider the macro invocation:

<code class="cpp">EXPAND_THESE(Property1, Property2, Property3, Property4)</code>
Copy after login
  • MSVC :

    1. VA_NARGS(Property1, Property2, Property3, Property4) -> 4
    2. SEMI_EXPANDED(4, Property1, Property2, Property3, Property4) -> MAC4(Property1, Property2, Property3, Property4)
    3. EXPAND_THESE(MAC4(Property1, Property2, Property3, Property4)) -> MAC4(Property1, Property2, Property3, Property4)
  • GCC:

    1. VA_NARGS(Property1, Property2, Property3, Property4) -> 4
    2. SEMI_EXPANDED(4, Property1, Property2, Property3, Property4) -> MAC4(Property1, Property2, Property3, Property4)
    3. EXPAND_THESE(MAC4(Property1, Property2, Property3, Property4)) -> MAC4(Property1, Property2, Property3, Property4)
      --> Further unfolds the MAC4 macro
      --> Equivalent to multiple lines of ACTUAL_MACRO calls

Workaround

To achieve similar behavior to GCC, one can employ Jeff Walden's approach, which involves creating additional macro helpers and using the COUNT_ARGS_MAX5 macro to determine the number of arguments:

<code class="cpp">#define FOO_CHOOSE_HELPER1(count) FOO##count
#define FOO_CHOOSE_HELPER2(count) FOO_CHOOSE_HELPER1(count)
#define FOO_CHOOSE_HELPER(count) FOO_CHOOSE_HELPER2(count)

#define ERROR(...) GLUE(FOO_CHOOSE_HELPER(COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__))

#define ASSERT1(expr) singleArgumentExpansion(expr)
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain)
#define ASSERT(...) GLUE(FOO_CHOOSE_HELPER(COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__))</code>
Copy after login

Alternatively, the abstraction provided by the "GLUE" macro can be used to simplify the workaround:

<code class="cpp">#define OVERLOAD_MACRO2(name, count) name##count
#define OVERLOAD_MACRO1(name, count) OVERLOAD_MACRO2(name, count)
#define OVERLOAD_MACRO(name, count) OVERLOAD_MACRO1(name, count)

#define CALL_OVERLOAD(name, ...) GLUE(OVERLOAD_MACRO(name, COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__))

#define ERROR1(title) printf("Error: %s\n", title);
#define ERROR2(title, message) \
    ERROR1(title); \
    printf("Message: %s\n", message);
#define ERROR(...) CALL_OVERLOAD(ERROR, __VA_ARGS__);

#define ASSERT1(expr) singleArgumentExpansion(expr)
#define ASSERT2(expr, explain) twoArgumentExpansion(expr, explain)
#define ASSERT(...) CALL_OVERLOAD(ASSERT, __VA_ARGS__);</code>
Copy after login

The above is the detailed content of Why Does Variadic Macro Expansion Differ Between MSVC and GCC?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!