Heim  >  Artikel  >  Backend-Entwicklung  >  Warum unterscheidet sich die Variadic-Makroerweiterung zwischen MSVC und GCC?

Warum unterscheidet sich die Variadic-Makroerweiterung zwischen MSVC und GCC?

Patricia Arquette
Patricia ArquetteOriginal
2024-11-05 08:36:02933Durchsuche

Why Does Variadic Macro Expansion Differ Between MSVC   and GCC?

Variadische Makroerweiterung in MSVC

Der variadische Makromechanismus in MSVC verhält sich anders als der in GCC, was zu Schwierigkeiten bei der Erweiterung von Makros führt mehrere Argumente. Betrachten Sie die folgenden Makros:

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

In GCC würde dieses Makro erweitert werden zu:

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

  Base * parent;
}</code>

In MSVC wird es jedoch erweitert zu:

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

  Base * parent;
}</code>

Erklärung

Das Problem entsteht, weil MSVC die Makroerweiterung Ebene für Ebene anwendet, während GCC Makros in einem Durchgang vollständig erweitert. Betrachten Sie den Makroaufruf:

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

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

    1. VA_NARGS(Eigenschaft1, Eigenschaft2, Eigenschaft3, Eigenschaft4) -> 4
    2. SEMI_EXPANDED(4, Property1, Property2, Property3, Property4) -> MAC4(Eigenschaft1, Eigenschaft2, Eigenschaft3, Eigenschaft4)
    3. EXPAND_THESE(MAC4(Eigenschaft1, Eigenschaft2, Eigenschaft3, Eigenschaft4)) -> MAC4(Eigenschaft1, Eigenschaft2, Eigenschaft3, Eigenschaft4)
      --> Entfaltet das MAC4-Makro weiter
      --> Entspricht mehreren Zeilen von ACTUAL_MACRO-Aufrufen

Workaround

Um ein ähnliches Verhalten wie GCC zu erreichen, kann man den Ansatz von Jeff Walden anwenden beinhaltet das Erstellen zusätzlicher Makro-Helfer und die Verwendung des COUNT_ARGS_MAX5-Makros, um die Anzahl der Argumente zu bestimmen:

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

Alternativ kann die vom „GLUE“-Makro bereitgestellte Abstraktion verwendet werden, um die Problemumgehung zu vereinfachen:

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

Das obige ist der detaillierte Inhalt vonWarum unterscheidet sich die Variadic-Makroerweiterung zwischen MSVC und GCC?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn