IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Expansion de macro incompréhensible


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2019
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2019
    Messages : 4
    Par défaut Expansion de macro incompréhensible
    Bonjour,
    je souhaiterais solliciter votre aide car je n'arrive pas du tout à comprendre l'expansion de cette macro pas à pas.

    Je connais le résultat : ça produit le 3ème code entre parenthèses si le 1er code est vide, sinon ça produit le 2nd.
    Cependant je n'arrive pas à comprendre à partir de quel moment on "bifurque" en fonction de si c'est vide ou pas.

    Est-ce qu'il y a des outils permettant de connaître pas à pas l'expansion d'une macro lorsqu'on est dans ce genre de cas afin de mieux la comprendre ?

    J'ai beau relire les commentaires ça ne m'aide pas bien évidemment...
    De manière plus générale je souhaiterais ré-utiliser ce code dans une autre macro de telle sorte qu'elle ne vérifie QUE si c'est vide ou pas, et non qu'elle inclue une production de code conditionnelle.

    Je ne sais pas si j'ai été très clair mais en tous les cas merci d'avance pour votre aide !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    #include <stdio.h>
     
    #define _IF_VALUE__SECOND(_a, _b, ...)		_b
    // _IF_VALUE__SECOND_2() does the same as _IF_VALUE__SECOND() after an additional round of parameter expansion.
    #define _IF_VALUE__SECOND_2(_a, _b, ...)	_IF_VALUE__SECOND(_a, _b, __VA_ARGS__)
    // _IF_VALUE__CHECK__IF_VALUE__IS_EMPTY() is used by _IF_VALUE__CHECK to test whether the argument is _IF_VALUE__IS_EMPTY and return _IF_VALUE__IS_EMPTY if so.
    #define _IF_VALUE__CHECK__IF_VALUE__IS_EMPTY()	~, _IF_VALUE__IS_EMPTY
    // _IF_VALUE__CHECK() produces _IF_VALUE__IS_EMPTY if _first is _IF_VALUE__IS_EMPTY and _IF_VALUE__NOT_EMPTY otherwise.
    #define _IF_VALUE__CHECK(_first, ...)		_IF_VALUE__SECOND_2(_IF_VALUE__CHECK_ ## _first (), _IF_VALUE__NOT_EMPTY, ~)
    // _IF_VALUE__CHECK_2() does the same as _IF_VALUE__CHECK() after an additional round of parameter expansion.
    #define _IF_VALUE__CHECK_2(_first, ...)		_IF_VALUE__CHECK(_first, __VA_ARGS__)
    // _IF_VALUE__IS_EMPTY takes 2 groups of parentheses and returns the unwrapped value of the first group.
    #define _IF_VALUE__IS_EMPTY(...)		_IF_VALUE__IS_EMPTY_1
    #define _IF_VALUE__IS_EMPTY_1(...)		__VA_ARGS__
    // _IF_VALUE__NOT_EMPTY takes 2 groups of parentheses and returns the unwrapped value of the second group.
    #define _IF_VALUE__NOT_EMPTY(...)		__VA_ARGS__ _IF_VALUE__NOT_EMPTY_1
    #define _IF_VALUE__NOT_EMPTY_1(...)		/* nothing */
    // IF_VALUE() produces _IF_VALUE__IS_EMPTY if _maybe_empty is empty and _IF_VALUE__NOT_EMPTY otherwise.
    #define IF_VALUE(_maybe_empty)	_IF_VALUE__CHECK_2(_IF_VALUE__CHECK _maybe_empty (_IF_VALUE__IS_EMPTY, ~), ~)
     
    int main()
    {
        int a = IF_VALUE()(2)(3);
        printf("%d", a);
     
        return 0;
    }

  2. #2
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Bonjour,
    Pour l'expansion, en Visual studio, il suffit de placer le curseur sur une macro pour qu'il propose "visualiser l'expansion". Ca donne ici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    int a = IF_VALUE()(2)(3);
    // _IF_VALUE__CHECK2(_IF_VALUE__CHECK(_IF_VALUE__IS_EMPTY, ~), ~)                           (2)(3)
    // _IF_VALUE__CHECK2(_IF_VALUE__SECOND_2(_IF_VALUE__CHECK__IF_VALUE__IS_EMPTY(),_IF_VALUE__NOT_EMPTY, ~), ~)   (2)(3)
    // _IF_VALUE__CHECK2(_IF_VALUE__SECOND(~, _IF_VALUE__IS_EMPTY,_IF_VALUE__NOT_EMPTY, ~), ~)  (2)(3)
    // _IF_VALUE__CHECK2(_IF_VALUE__IS_EMPTY, ~)                                                (2)(3)
    // _IF_VALUE__CHECK( _IF_VALUE__IS_EMPTY, ~)                                                (2)(3)
    // _IF_VALUE__SECOND_2(_IF_VALUE__CHECK__IF_VALUE__IS_EMPTY(), _IF_VALUE__NOT_EMPTY, ~)     (2)(3)
    // _IF_VALUE__SECOND_2(~, _IF_VALUE__IS_EMPTY, _IF_VALUE__NOT_EMPTY, ~)                     (2)(3)
    // _IF_VALUE__IS_EMPTY(2)  (3)
    // _IF_VALUE__IS_EMPTY_1   (3)
    // 3
     
    int b = IF_VALUE(1)(2)(3);
    // _IF_VALUE__CHECK_2(_IF_VALUE__CHECK  1  (_IF_VALUE__IS_EMPTY, ~), ~) (2)(3)
    // _IF_VALUE__CHECK(  _IF_VALUE__CHECK  1  (_IF_VALUE__IS_EMPTY, ~), ~) (2)(3)
    // _IF_VALUE__SECOND_2(_IF_VALUE__CHECK__IF_VALUE__CHECK  1  (_IF_VALUE__IS_EMPTY, ~)(), _IF_VALUE__NOT_EMPTY, ~) (2)(3)
    // _IF_VALUE__SECOND(  _IF_VALUE__CHECK__IF_VALUE__CHECK  1  (_IF_VALUE__IS_EMPTY, ~)(), _IF_VALUE__NOT_EMPTY, ~) (2)(3)
    // _IF_VALUE__NOT_EMPTY(2) (3)
    // 2 _IF_VALUE__NOT_EMPTY_1(3)
    // 2
    En fait, j'ai dû corriger l'expansion, il semble que Visual studio gère mal #define _IF_VALUE__SECOND(_a, _b, ...) _b et retourne dans ce cas le dernier paramètre non vide au lieu du second!

    A quel moment il y a "bifurcation" due au paramètre vide? c'est au tout début:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #define IF_VALUE(_maybe_empty)	_IF_VALUE__CHECK_2(_IF_VALUE__CHECK _maybe_empty (_IF_VALUE__IS_EMPTY, ~), ~)
    // donne si le champ est vide:
    _IF_VALUE__CHECK_2(_IF_VALUE__CHECK  (_IF_VALUE__IS_EMPTY, ~), ~)
    // donne si le champ n'est pas vide
    _IF_VALUE__CHECK_2(_IF_VALUE__CHECK   quelque_chose_ici (_IF_VALUE__IS_EMPTY, ~), ~)
    Et ça change tout. Dans le premier cas _IF_VALUE__CHECK est une macro qui reçoit bien son paramètre et est interprétée. Dans ce second, il n'y a pas de parenthèse après _IF_VALUE__CHECK et le mot _IF_VALUE__CHECK reste là sans être interprété. C'est aussi le cas de _IF_VALUE__IS_EMPTY qui restera inchangé et pourtant c'est bien une macro utilisée ailleurs avec son paramètre!

    J'aurais écris ça plus simplement en utilisant une macro qui attend 3 paramètres dont le premier peut être vide, au lieu d'une séquence de trois expressions entre parenthèses:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # define  _EN_SECOND(p2)                p1 , p2
    # define  _LE_SECOND2( p1, p2, ... )    p2
    # define  _LE_SECOND( p1, p2, ... )     _LE_SECOND2( p1, p2, __VA_ARGS__ )
    # define  SI_QQCH_X_sinon_Y(tst,p2,p3)  _LE_SECOND( _EN_SECOND  tst  (p3) ,  p2 )
     
     
    # define  RIEN
    # define  DEUX     1+1
    # define  TROIS   3*1
       int  g = SI_QQCH_X_sinon_Y( , 2, 3 );
       int  h = SI_QQCH_X_sinon_Y( RIEN, DEUX, TROIS );
       int  i = SI_QQCH_X_sinon_Y( 1, DEUX, TROIS );
       printf( "%d %d %d\n", g, h, i );

  3. #3
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2019
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2019
    Messages : 4
    Par défaut
    Me voilà de retour,
    bon, j'ai potassé le sujet pendant une semaine complète pendant mon temps libre, et il s'avère que la meilleure solution reste de tout simplement compter le nombre d'arguments.
    C'est simple, s'il y en a pas, c'est que c'est vide (je "renvois" alors 1 au niveau préprocesseur), sinon, c'est qu'il y en a (je "renvois" alors 0). C'est ce que je voulais obtenir sans rien d'autre.

    Pour m'aider, je fais appel à une feature qui consiste à "avaler" la virgule lorsqu'il n'y a pas d'arguments dans __VA_ARGS__ :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #define NB_ARGS_(_0, _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, _33_, _34_, _35_, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, count, ...) count
    #define IF_EMPTY(...) NB_ARGS_(0, ##__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)
    Ainsi, on obtient 71 arguments (et non pas 72) plus tard un count qui n'est autre que 1, ça aurait été 0 si on avait eu 1 argument ou plus. Voilà la macro servant à donner le nombre d'arguments exact sur laquelle se base la mienne, et ce, sans problème dû au fait d'une virgule en trop lorsque l'on a rien :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define NB_ARGS(...) NB_ARGS_(0, ##__VA_ARGS__, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    Ainsi, on a bien un count à 70 par exemple si on a une macro contenant 70 arguments, et donc, plutôt que de donner le nombre d'arguments cette fois-ci, je donne tout simplement 0 ou 1 selon le besoin pour ma macro IF_EMPTY.

    C'est une macro que j'avais déjà dans mon code depuis longtemps et au final je me sens un peu con de ne pas tout simplement avoir pensé à l'utiliser avant mais bref...

    Oui, parce que les 2 autres macros posent plusieurs problèmes :
    1) IF_VALUE() nécessite 3 expressions, si on ne souhaite que connaître le résultat du test, ça fait énormément d'expansions pour pas grand chose, surtout quand c'est vide, et c'était pour ma part un vrai casse tête avant d'arriver à un résultat compréhensible par l'expansion pas à pas de tête, car je n'ai pas la feature de l'expansion pas à pas sur mon IDE. Je me noyais vraiment dans cet ensemble de macros, le jour où j'ai un soucis avec, je n'ose imaginer le temps passé au débugage !
    2) La 1ère expression "renvoie" vide si on ajoute des parenthèses dedans quoi qu'on y mette, en effet la macro _IF_VALUE__CHECK est de fait interprétée, et du coup, on suit la logique d'expansions jusqu'à produire la 3ème expression comme si c'était vide, or ce résultat n'est pas bon.
    3) La 1ère expression ne peut pas être une vraie expression car elle ne prend en compte qu'un seul paramètre à la fois, sauf que comme vu précédemment, lorsque l'on garde avec des parenthèses pour envoyer une série de paramètres par exemple, ça "renvoie" vide quand même.
    4) Je compte beaucoup utiliser cette macro qui check si une expression est vide ou pas, pour d'autres macros qui instancient des choses, or il me faut pouvoir produire du code en fonction de si certains paramètres sont présents ou non, ce n'est pas au runtime que ça se passe, donc j'ai besoin d'avoir des infos avant même la compilation. Or, avoir autant d'expansions juste pour un check ce n'est pas souhaitable, question de performance.
    5) ta macro SI_QQCH_X_sinon_Y() est plus simple certes mais ne supporte que 3 paramètres atomiques, si je veux utiliser des expressions complexes, c'est mort.

    Voici donc à nouveau le code complet, mon analyse pas à pas en commentaire pour la 1ère macro ainsi que le résultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    #include <stdio.h>
    #include <stdbool.h>
     
    #define _IF_VALUE__SECOND(_a, _b, ...) _b
    #define _IF_VALUE__SECOND_2(_a, _b, ...) _IF_VALUE__SECOND(_a, _b, __VA_ARGS__)
    #define _IF_VALUE__CHECK__IF_VALUE__IS_EMPTY() ~, _IF_VALUE__IS_EMPTY
    #define _IF_VALUE__CHECK(_first, ...) _IF_VALUE__SECOND_2(_IF_VALUE__CHECK_ ## _first (), _IF_VALUE__NOT_EMPTY, ~)
    #define _IF_VALUE__CHECK_2(_first, ...) _IF_VALUE__CHECK(_first, __VA_ARGS__)
    #define _IF_VALUE__IS_EMPTY(...) _IF_VALUE__IS_EMPTY_1
    #define _IF_VALUE__IS_EMPTY_1(...) __VA_ARGS__
    #define _IF_VALUE__NOT_EMPTY(...) __VA_ARGS__ _IF_VALUE__NOT_EMPTY_1
    #define _IF_VALUE__NOT_EMPTY_1(...)
    #define IF_VALUE(_maybe_empty) _IF_VALUE__CHECK_2(_IF_VALUE__CHECK _maybe_empty (_IF_VALUE__IS_EMPTY, ~), ~)
     
    # define IN_SECOND(p2)                  p1, p2
    # define SECOND_(p1, p2, ...)           p2
    # define SECOND(p1, p2, ...)            SECOND_(p1, p2, __VA_ARGS__)
    # define IF_SOME(maybe_empty, p2, p3)   SECOND(IN_SECOND  maybe_empty  (p3), p2)
     
    #define NB_ARGS_(_0, _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, _33_, _34_, _35_, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, count, ...) count
    #define IF_EMPTY(...) NB_ARGS_(0 __VA_OPT__(,) __VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)
     
    int main()
    {
        bool a = IF_SOME(, 1, 0);
        bool d = IF_VALUE()(1)(0);
        bool g = IF_EMPTY();
        /*
        _IF_VALUE__CHECK_2(_IF_VALUE__CHECK  (_IF_VALUE__IS_EMPTY, ~), ~)(1)(0)
        _IF_VALUE__CHECK_2(_IF_VALUE__SECOND_2(_IF_VALUE__CHECK_ ## _IF_VALUE__IS_EMPTY (), _IF_VALUE__NOT_EMPTY, ~), ~)(1)(0)
        _IF_VALUE__CHECK_2(_IF_VALUE__SECOND_2(~, _IF_VALUE__IS_EMPTY, _IF_VALUE__NOT_EMPTY, ~), ~)(1)(0)
        _IF_VALUE__CHECK_2(_IF_VALUE__SECOND(~, _IF_VALUE__IS_EMPTY, _IF_VALUE__NOT_EMPTY, ~), ~)(1)(0)
        _IF_VALUE__CHECK_2(_IF_VALUE__IS_EMPTY, ~)(1)(0)
        _IF_VALUE__CHECK(_IF_VALUE__IS_EMPTY, ~)(1)(0)
        _IF_VALUE__SECOND_2(_IF_VALUE__CHECK_ ## _IF_VALUE__IS_EMPTY (), _IF_VALUE__NOT_EMPTY, ~)(1)(0)
        _IF_VALUE__SECOND_2(~, _IF_VALUE__IS_EMPTY, _IF_VALUE__NOT_EMPTY, ~)(1)(0)
        _IF_VALUE__SECOND(~, _IF_VALUE__IS_EMPTY, _IF_VALUE__NOT_EMPTY, ~)(1)(0)
        _IF_VALUE__IS_EMPTY(1)(0)
        _IF_VALUE__IS_EMPTY_1(0)
        0
        */
        bool b = IF_SOME(2, 1, 0);
        bool e = IF_VALUE(2)(1)(0);
        bool h = IF_EMPTY(2);
        /*
        _IF_VALUE__CHECK_2(_IF_VALUE__CHECK 1 (_IF_VALUE__IS_EMPTY, ~), ~)(1)(0)
        _IF_VALUE__CHECK(_IF_VALUE__CHECK 1 (_IF_VALUE__IS_EMPTY, ~), ~)(1)(0)
        _IF_VALUE__SECOND_2(_IF_VALUE__CHECK_ ## _IF_VALUE__CHECK 1 (_IF_VALUE__IS_EMPTY, ~)(), _IF_VALUE__NOT_EMPTY, ~)(1)(0)
        _IF_VALUE__SECOND_2(_IF_VALUE__CHECK__IF_VALUE__CHECK 1 (_IF_VALUE__IS_EMPTY, ~)(), _IF_VALUE__NOT_EMPTY, ~)(1)(0)
        _IF_VALUE__SECOND(_IF_VALUE__CHECK__IF_VALUE__CHECK 1 (_IF_VALUE__IS_EMPTY, ~)(), _IF_VALUE__NOT_EMPTY, ~)(1)(0)
        _IF_VALUE__NOT_EMPTY(1)(0)
        1 _IF_VALUE__NOT_EMPTY_1(0)
        1
        */
        bool c = IF_SOME(a(2,3), 1, 0);
        bool f = IF_VALUE((2,3))(1)(0);
        bool i = IF_EMPTY(a,{((2,3)]););
     
        printf("IF_SOME(, 1, 0) = %d et %s\nIF_VALUE()(1)(0) = %d et %s\nIF_EMPTY() = %d et %s\n\n", a, a ? "contient quelque chose" : "ne contient rien", d, d ? "a une valeur" : "n'a pas de valeur", g, g ? "est vide" : "n'est pas vide");
        printf("IF_SOME(2, 1, 0) = %d et %s\nIF_VALUE(2)(1)(0) = %d et %s\nIF_EMPTY(2) = %d et %s\n\n", b, b ? "contient quelque chose" : "ne contient rien", e, e ? "a une valeur" : "n'a pas de valeur", h, h ? "est vide" : "n'est pas vide");
        printf("IF_SOME(a(2,3), 1, 0) = %d et %s\nIF_VALUE((2,3))(1)(0) = %d et %s\nIF_EMPTY(a,{((2,3)]);) = %d et %s", c, c ? "contient quelque chose" : "ne contient rien", f, f ? "a une valeur" : "n'a pas de valeur", i, i ? "est vide" : "n'est pas vide");
     
        return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    IF_SOME(, 1, 0) = 0 et ne contient rien -> compliant sachant que s'il n'y a rien, on renvoie vide, donc le 3ème paramètre, qui vaut 0
    IF_VALUE()(1)(0) = 0 et n'a pas de valeur -> compliant sachant que s'il n'y a rien, on renvoie vide, donc la 3ème expression, qui vaut 0
    IF_EMPTY() = 1 et est vide -> compliant sachant que s'il y a 0 argument, on renvoie 1
    
    IF_SOME(2, 1, 0) = 1 et contient quelque chose -> compliant sachant que s'il y a quelque chose, on renvoie le 2ème paramètre, qui vaut 1
    IF_VALUE(2)(1)(0) = 1 et a une valeur -> compliant sachant que s'il y a quelque chose, on renvoie la 2ème expression, qui vaut 1
    IF_EMPTY(2) = 0 et n'est pas vide -> compliant sachant que s'il y a au moins un argument, on renvoie 0
    
    IF_SOME(a(2,3), 1, 0) = 1 et contient quelque chose -> non compliant car on est obligé de rajouter des éléments pour que le paramètre soit accepté (ici j'ai rajouté le a devant les parenthèses)
    IF_VALUE((2,3))(1)(0) = 0 et n'a pas de valeur -> non compliant car le résultat est faux, la 1ère expression n'est pas vide !
    IF_EMPTY(a,{((2,3)]);) = 0 et n'est pas vide -> compliant quelque soit la complexité de l'expression
    
    ...Program finished with exit code 0
    Press ENTER to exit console.
    Merci en tous les cas pour ton aide, car finalement tu m'as bien aidé à mieux comprendre la macro sans m'embrouiller.
    J'ai bien conscience que ma solution a aussi des défauts, du genre l'utilisation de l'extension non portable pour la gestion d'un __VA_ARGS__ vide, le nombre arbitraire limité de 70 arguments, ou encore le fait que la réutilisation de la macro du comptage d'argument entraîne beaucoup de duplication de code pour peu qu'on ait besoin d'autres résultats pour d'autres usages.
    Mais je la trouve plus simple que la IF_VALUE() déjà, ensuite l'extension non portable de ce que j'ai vu peut être remplacée par __VA_OPT__ qui a été intégré au C23 (j'ai mis à jour mon programme de test à cet effet) le nombre de 70 arguments pour ma part couvre tous les besoins pour le moment, et la duplication de code eh bien il faudra que je fasse en sorte de factoriser cette partie je dirais
    Bonne fin de semaine à ceux que ça a intéressé en tous les cas !

Discussions similaires

  1. Macro C, expansion d'un define
    Par Maitre_Kanter dans le forum C
    Réponses: 15
    Dernier message: 09/12/2016, 14h42
  2. [IDE] E2222 : Expansion de macro trop longue
    Par Didier44 dans le forum C++Builder
    Réponses: 2
    Dernier message: 27/01/2012, 09h05
  3. [VBA-E] [Excel] Lancer une macro à une heure donnée
    Par Lysis dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 16/10/2002, 12h15
  4. Qu'est-ce qu'une macro ?
    Par karli dans le forum Assembleur
    Réponses: 2
    Dernier message: 01/09/2002, 03h38
  5. Réponses: 2
    Dernier message: 22/07/2002, 12h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo