Maison > Article > développement back-end > Pourquoi l’expansion macro variadique de MSVC diffère-t-elle de celle de GCC, et comment pouvons-nous surmonter cet écart ?
Extension de macros variadiques MSVC
Les macros variadiques offrent des capacités d'expansion polyvalentes, vous permettant de gérer plusieurs arguments dans les macros. Dans GCC, les macros telles que celles-ci fonctionnent comme prévu :
<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>
Comportement d'expansion MSVC
Cependant, dans le compilateur C de Microsoft (MSVC), l'expansion des macros se comporte différemment . Au lieu de développer chaque argument séparément, MSVC concatène tous les arguments en une seule expression.
struct MyStructure<br>{<br> void Foo()<br> {</p> <pre class="brush:php;toolbar:false">EXPAND_THESE(Property1, Property2, Property3, Property4)
}
Base * parent;
};
Extension GCC :
{<br> void Foo()<br> {</p><pre class="brush:php;toolbar:false">parent->GetProperty<Property1>(); parent->GetProperty<Property2>(); parent->GetProperty<Property3>(); parent->GetProperty<Property4>();</p> <p>}</p> <p>Base * parent;<br>}<br>
Extension MSVC :
struct MyStructure<br>{<br> void Foo()<br> {</p> <pre class="brush:php;toolbar:false">parent->GetProperty<Property1, Property2, Property3, Property4>();
>
Base * parent;
}
Solution :
Jeff Walden a proposé une solution de contournement en utilisant le modèle suivant :
<code class="cpp">#define ERRORn(...) ERROR_CHOOSE_HELPERn(COUNT_ARGS_MAX5(__VA_ARGS__), __VA_ARGS__) #define ERROR_CHOOSE_HELPER1(count) ERROR1 #define ERROR_CHOOSE_HELPER2(count) ERROR2 #define ERROR_CHOOSE_HELPER(count) ERROR_CHOOSE_HELPER##count</code>
Cette approche nécessite de définir une macro CHOOSE_HELPER pour chaque nombre de macros variadiques souhaité (par exemple, ERROR1, ERROR2, etc.). Cependant, il est essentiel de déclarer chaque macro CHOOSE_HELPER dans le cadre de la définition de la macro variadique.
Une solution plus concise et portable consiste à exploiter la technique suivante :
<code class="cpp">#define GLUE(x, y) x y #define RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, count, ...) count #define EXPAND_ARGS(args) RETURN_ARG_COUNT args #define COUNT_ARGS_MAX5(...) EXPAND_ARGS((__VA_ARGS__, 5, 4, 3, 2, 1, 0)) #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__))</code>
Avec cette configuration , les macros peuvent être définies comme :
<code class="cpp">#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>
En utilisant la hiérarchie OVERLOAD_MACRO, il est possible d'éviter de définir des macros CHOOSE_HELPER.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!