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 :

Problème macro a paramètre


Sujet :

C

  1. #1
    Nouveau Candidat au Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 24
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 5
    Points : 1
    Points
    1
    Par défaut Problème macro a paramètre
    Bonjour,

    Je veux créer une macro qui transforme le contenu de son paramètre en sa valeur absolue.

    Une solution qui marche est la suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define ABS(x) (((x) < 0) ? -(x) : (x))
    Mais cette solution (qui pour moi veux dire la même chose ne fonctionne pas .
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    #define ABS(Value) if (Value>=0)\
                            Value=Value;\
                        else if (Value<0)\
                            Value*=-1;
    J'aimerais comprendre pourquoi.

    Merci

  2. #2
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 380
    Points
    1 380
    Par défaut
    Bonjour,
    donner un exemple qui montre «ce qui ne fonctionne pas» est toujours plus parlant. Mais je peux me douter
    La première macro est une expression qui a une valeur; la seconde est du code qui n'a pas de valeur. De plus ces macros ne sont pas très cools si tu donnes comme paramètre quelque chose comme : i++ …

    Sinon, quand tu fais une macro comme celle-ci, il est préférable de l'encadrer par une fausse boucle while :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #define ABS(Value) do { \
                        if (Value>=0)\
                            Value=Value;\
                        else if (Value<0)\
                            Value*=-1;
                    } while(0)
    Mais ce qui est encore mieux → les fonctions static inline parce qu'en plus d'être une vraie fonction évite tous les problèmes inhérents aux macros →
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    static inline int abs(int a)
    {
        return a<0?-a:a;
    }
    Désavantage : il te faut une fonction par type (en gros).

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 675
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 675
    Points : 10 689
    Points
    10 689
    Par défaut
    Citation Envoyé par Carlaaaa1111 Voir le message
    qui pour moi veux dire la même chose ne fonctionne pas
    Certes mais cela ne veut pas dire que tu peux utiliser la nouvelle macro de la même manière.

    1 test ternaire permet d'être inséré dans 1 ligne de code (1 return, 1 paramètre d'1 fonction par exemple) au contraire d'1 test classique qui lui est X lignes de code.

    Et soit dit en passant , si 1 nombre n'est pas positif ni nul, il est forcément négatif donc else if (Value<0) est inutile.

  4. #4
    Nouveau Candidat au Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 24
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 5
    Points : 1
    Points
    1
    Par défaut
    Citation Envoyé par WhiteCrow Voir le message
    Bonjour,
    donner un exemple qui montre «ce qui ne fonctionne pas» est toujours plus parlant. Mais je peux me douter
    La première macro est une expression qui a une valeur; la seconde est du code qui n'a pas de valeur. De plus ces macros ne sont pas très cools si tu donnes comme paramètre quelque chose comme : i++ …
    Par exemple si je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #define ABS(Value) if (Value>=0)\
                            Value=Value;\
                        else if (Value<0)\
                            Value*=-1;
     
    int main (int argc, char **argv)
    {
                   int Value;
     
                   ABS(-5)
     
                   printf("%d", Value);
     
    }
    Mon compilateur affiche :
     In function ‘main’:
    ft_abs.h:2:30: error: lvalue required as left operand of assignment
        2 |                         Value=Value;\
          |                              ^
    exo02.c:7:2: note: in expansion of macro ‘ABS’
        7 |  ABS(-5)
          |  ^~~
    ft_abs.h:4:30: error: lvalue required as left operand of assignment
        4 |                         Value*=-1;
          |                              ^~
    exo02.c:7:2: note: in expansion of macro ‘ABS’
        7 |  ABS(-5)
          |  ^~~
    Pourtant ABS(-5) devrait être remplacé par la macro non ?

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 675
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 675
    Points : 10 689
    Points
    10 689
    Par défaut
    C'est normal ton paramètre de ta macro a le même nom qu'1 variable. @Sve@r a raison , le problème est que tu fais 1 auto-affectation qui 1) ne sert à rien si c'est 1 variable 2) plante avec 1 valeur fixe (ton problème justement)
    Et effectivement je n'ai pas vu le problème

    Et donc Value=Value; tu crois que cela faire quoi ? Simple, si tu passes en paramètre -5, alors tu vas avoir -5=-5 et -5*=-1.
    Ton compilateur te dit gentiment qu'il ne pas faire d'affectation dans 1 valeur fixe : ce qui est logique

  6. #6
    Nouveau Candidat au Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 24
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 5
    Points : 1
    Points
    1
    Par défaut
    Ah je vois et donc en écrivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #define ABS(Value) if (Value>=0)\
                           result=Value;\
                        else if (Value<0)\
                            result=Value*-1;
     
    int main (int argc, char **argv)
    {
                   int result;
     
                   ABS(-5)
     
                   printf("%d", result);
     
    }
    Ca fonctionne! Par contre dans ces cas la je ne respecte pas l'énoncé qui dit "Ecrire une macro qui remplace son paramêtre pas sa valeur absolue" car Value n'est pas modifié

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 130
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 130
    Points : 33 063
    Points
    33 063
    Billets dans le blog
    4
    Par défaut
    Une macro n'est pas un truc magique. Ça remplace la macro par le code de la macro.
    -5 n'est pas une variable, donc ta syntaxe est incorrecte.
    Value n'est pas modifié
    Value n'existe pas, dans la macro ce sera -5. Effectivement tu vas difficilement modifier la valeur d'un truc qui n'est pas une variable.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int result = -5;
    ABS(result);
    Et voilà.

  8. #8
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 735
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 735
    Points : 31 060
    Points
    31 060
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Carlaaaa1111 Voir le message
    Ca fonctionne!
    Oui ça fonctionne mais c'est une des pires solutions qui soient car la macro n'a aucune indépendance vis à vis du reste du programme. Elle ne peut être utilisée qu'en partenariat avec une variable "result" (donc en fait à un seul endroit ce qui limite un peu son utilité) et si cette variable change ou disparait suite à évolution, tout le programme s'écroule.

    Ton tout premier exemple (la solution qui fonctionne) reste encore ce qu'il y a de mieux

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #define ABS(x) ((x) < 0 ?-(x) :(x))
     
    int main (int argc, char **argv) {
    	int Value=ABS(-5);
    	printf("%d", Value);
    }

    Citation Envoyé par Carlaaaa1111 Voir le message
    Mais cette solution (qui pour moi veux dire la même chose) ne fonctionne pas .
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    #define ABS(Value) if (Value>=0)\
                            Value=Value;\
                        else if (Value<0)\
                            Value*=-1;
    Elle ne veut pas dire la même chose. La première solution exprime une opération mathématique basée sur un opérateur du C. Exactement comme tu aurais pu exprimer un carré de cette façon #define CARRE(x) ((x) * (x)). Et elle pourra être utilisée dans toute circonstance où une expression algébrique (constante, calcul) est acceptée (affectation, paramètre de fonction, if(), while(), for()).
    Cette second solution est déjà un bout de code avec une condition et une affectation. Ok au résultat c'est la même chose mais du point de vue C, ce n'est plus du tout pareil car le cheminement pour arriver au résultat n'est plus le même.
    Accessoirement je n'arrive pas vraiment à percevoir l'utilité profonde de ce Value=Value...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #define ABS(Value) if (Value<0) Value=-Value
     
    int main (int argc, char **argv) {
    	int Value=-5;
     
    	ABS(Value);
    	printf("%d", Value);
    }
    De plus, tu remarqueras que je n'ai pas mis de point-virgule à la fin de la macro. Ceci afin de pouvoir l'utiliser dans une expression où le point-virgule est interdit (paramètre d'une fonction, if(), while(), for()). Mais évidemment comme dans ce type d'expression l'affectation est elle-aussi interdite...

    Citation Envoyé par Carlaaaa1111 Voir le message
    Par contre dans ces cas la je ne respecte pas l'énoncé qui dit "Ecrire une macro qui remplace son paramêtre pas sa valeur absolue" car Value n'est pas modifié
    Effectivement l'énoncé est incorrectement formulé. Une macro n'a pas pour vocation de remplacer son paramètre par autre chose, mais d'utiliser le paramètre dans une expression.
    Ou alors l'énoncé est bien formulé et alors jamais il n'aurait dû te venir à l'idée de lui passer une valeur directe et donc non modifiable

    Citation Envoyé par foetus Voir le message
    C'est normal ton paramètre de ta macro a le même nom qu'1 variable.
    Cela n'a pas d'importance, les variables locales sont indépendantes de ce qui est en global (exactement comme tu pourrais créer une int Value en global sans perturber le compilateur). Tu peux reprendre mon premier exemple de ce post et remplacer "x" par "Value" ça fonctionnera. C'est parce que le pré-processeur fait une première passe et remplace toutes les macros par leur équivalent. Quand l'analyseur syntaxique arrive, il reçoit un code sans aucune macro et donc ne voit pas de paramètre identique à la variable.

  9. #9
    Nouveau Candidat au Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 24
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 5
    Points : 1
    Points
    1
    Par défaut
    Merci à tous pour vos réponses je commence a saisir le principe.

    Y'aurait-il d'autres solutions possible histoire que je comprenne bien comment ça marche?

    Citation Envoyé par Sve@r Voir le message
    Bonjour

    Oui ça fonctionne mais c'est une des pires solutions qui soient car la macro n'a aucune indépendance vis à vis du reste du programme. Elle ne peut être utilisée qu'en partenariat avec une variable "result" (donc en fait à un seul endroit ce qui limite un peu son utilité) et si cette variable change ou disparait suite à évolution, tout le programme s'écroule.

    ton tout premier exemple (la solution qui fonctionne) reste encore ce qu'il y a de mieux

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define ABS(x) ((x) < 0 ?-(x) :(x))
    D'accord je vois mais je n'ai pas bien compris dans cette exemple ca remplace le code par ((x) < 0 ?-(x) : (x)) ou ca remplace le code par x si x>0 et par -x si x<0 ?

  10. #10
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 735
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 735
    Points : 31 060
    Points
    31 060
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Carlaaaa1111 Voir le message
    D'accord je vois mais je n'ai pas bien compris dans cette exemple ca remplace le code par ((x) < 0 ?-(x) : (x)) ou ca remplace le code par x si x>0 et par -x si x<0 ?
    Une macro remplace intégralement "x" par ce que tu lui mets. Exemple ABS(1-8) donnera ((1-8) < 0 ?-(1-8) :(1-8)). C'est d'ailleurs pour ça qu'on place "x" entre parenthèse à chaque fois qu'on l'utilise. Et les parenthèses globales permettent d'intégrer la macro dans un calcul plus large sans avoir de souci de priorité.
    Ne reste que le cas du ABS(i++) qui donnera ((i++) < 0 ?-(i++) :(i++)) produisant alors un lourd effet de bord impossible à résoudre. C'est pour ça qu'on ne met jamais d'opération d'auto-modification quand on appelle une macro (d'où l'écriture en majuscules pour permettre de la repérer). Sauf que certaines fonctions sont en réalité des macros cachées pour accélérer l'appel (ex isupper()) et que de façon plus générale, il vaut mieux ne jamais mettre d'opération d'auto-modification en paramètre d'une fonction (parce que franchement, entre fct(i++) et fct(i); i++ la première écriture n'est là que pour se la pêter et ne change absolument rien à la vitesse du code tout en pouvant tout faire crasher si fct() est en réalité une macro qui utilise plusieurs fois son paramètre).

    Et éventuellement ne plus utiliser de macro paramétrée et utiliser le inline montré par WhiteCrow qui nous vient du C++.

  11. #11
    Nouveau Candidat au Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Novembre 2020
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 24
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2020
    Messages : 5
    Points : 1
    Points
    1
    Par défaut
    D'accord je comprend mieux merci. Je vais continuer a m'entrainer.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XSL] Problème apostrophe dans paramètre
    Par jeyce dans le forum XSL/XSLT/XPATH
    Réponses: 5
    Dernier message: 28/03/2006, 18h46
  2. [xsl] Problème hyperlink avec paramètre
    Par ekmule dans le forum XSL/XSLT/XPATH
    Réponses: 1
    Dernier message: 13/12/2005, 09h46
  3. [NEWBIE] Problème passage en paramètre
    Par Goundy dans le forum Langage
    Réponses: 4
    Dernier message: 22/10/2005, 21h18
  4. [Débutant] Problème avec les paramètres d'une proc stockée
    Par babulior dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 28/06/2005, 16h38
  5. Problème avec les paramètres date BDE/ODBC Oracle/XP Pro
    Par Bloon dans le forum Bases de données
    Réponses: 3
    Dernier message: 06/10/2004, 11h09

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