Le besoin de parenthèses dans les macros en C [dupliquer]

cette question a déjà une réponse ici:

  • C macros et l'utilisation d'arguments entre parenthèses 2 réponses

j'ai essayé de jouer avec la définition de la macro SQR dans le code suivant:

#define SQR(x) (x*x)
int main()
{
    int a, b=3;
    a = SQR(b+5);      // Ideally should be replaced with (3+5*5+3), though not sure.
    printf("%dn",a);
    return 0;
}

il imprime 23 . Si Je changer la macro définition à SQR(x) ((x)*(x)) puis la sortie est comme prévu, 64 . Je sais qu'un appel à une macro en C remplace l'appel par la définition de la macro, mais je ne comprends toujours pas, comment il a calculé 23 .

25
demandé sur Palec 2012-05-30 20:25:26

8 réponses

les macros de pré-processeur effectuent le remplacement du texte avant que le code ne soit compilé ainsi SQR(b+5) se traduit par (b+5*b+5) = (6b+5) = 6*3+5 = 23

les appels de fonction réguliers calculeraient la valeur du paramètre (b+3) avant de le passer à la fonction, mais puisqu'une macro est un remplacement précompilé, l'ordre algébrique des opérations devient très important.

27
répondu Babak Naffas 2013-09-25 00:36:05

parce que (3+5*3+5 == 23) .

alors que ((3+5)*(3+5)) == 64 .

la meilleure façon de faire cela est de ne pas utiliser une macro :

inline int SQR(int x) { return x*x; }

ou écrivez simplement x*x .

10
répondu Luchian Grigore 2012-05-30 16:28:00

envisager le remplacement macro en utilisant cette macro:

#define SQR(x) (x*x)

utilisant b+5 comme argument. Faire le remplacement vous-même. Dans votre code, SQR(b+5) deviendra: (b+5*b+5) , ou (3+5*3+5) . Maintenant, rappelez-vous votre opérateur priorité règles: * avant + . C'est évalué comme: (3+15+5) , ou 23 .

la deuxième version de la macro:

#define SQR(x) ((x) * (x))

est correct, parce que vous utilisez le parens pour développer vos arguments macro à partir des effets de priorité de l'opérateur.

Cette page , expliquant opérateur préférence pour le C a un beau tableau. Voici de la section pertinente de la C11 document de référence.

la chose à se rappeler ici est que vous devriez prendre l'habitude de toujours protéger les arguments dans vos macros, à l'aide de parenthèses.

7
répondu pb2q 2018-03-23 14:51:50

la macro se développe en

 a = b+5*b+5;

c'est à dire

 a = b + (5*b) + 5;

Donc 23.

6
répondu Mat 2012-05-30 16:27:30

une macro n'est qu'une simple substitution de texte. Après prétraitement, votre code ressemble à:

int main()
{
    int a, b=3;
    a = b+5*b+5;
    printf("%d\n",a);
    return 0;
}
La Multiplication

a un opérateur de priorité plus élevé que l'addition, donc c'est fait avant les deux additions lors du calcul de la valeur pour a . Ajouter des parenthèses à votre définition de macro corrige le problème en le faisant:

int main()
{
    int a, b=3;
    a = (b+5)*(b+5);
    printf("%d\n",a);
    return 0;
}

les opérations entre parenthèses sont évaluées avant la multiplication, de sorte que les additions arrive d'abord maintenant, et vous obtenez le résultat a = 64 que vous attendez.

2
répondu Caleb 2012-05-30 16:34:44

Après prétraitement, SQR(b+5) sera étendu à (b+5*b+5) . Ce n'est évidemment pas correct.

il y a deux erreurs communes dans la définition de SQR :

  1. ne pas inclure les arguments de macro entre parenthèses dans le corps de macro, donc si ces arguments sont des expressions, les opérateurs avec des précédents différents dans ces expressions peuvent causer des problèmes. Voici une version qui a corrigé ce problème ""

    #define SQR(x) ((x)*(x))
    
  2. évaluer les arguments de macro plus d'une fois, donc si ces arguments sont des expressions qui ont des effets secondaires, ces effets secondaires pourraient être pris plus d'une fois. Par exemple, considérons le résultat de SQR(++x) .

    en utilisant GCC type de extension, ce problème peut être corrigé comme ceci

    #define SQR(x) ({ typeof (x) _x = (x); _x * _x; })
    

ces Deux problèmes pourraient être résolus par remplacement de cette macro par une fonction en ligne

   inline int SQR(x) { return x * x; }

cela nécessite une extension en ligne GCC ou C99, voir 6.40 une fonction en ligne est aussi rapide qu'une Macro .

2
répondu Lee Duhem 2014-05-27 12:52:57

parce que les Macros ne sont que des remplacements de chaîne et cela se produit avant le processus d'achèvement. Le compilateur n'aura pas la chance de voir la variable Macro et sa valeur. Par exemple: si une macro est définie comme

#define BAD_SQUARE(x)  x * x 

et appelé comme ceci

BAD_SQUARE(2+1) 

le compilateur verra ce

2 + 1 * 2 + 1

ce qui entraînera, peut-être, un résultat inattendu de

5

à corrigez ce comportement, vous devriez toujours entourer les macro-variables de parenthèses, comme

#define GOOD_SQUARE(x)  (x) * (x) 

quand cette macro est appelée, par exemple, comme ceci

GOOD_SQUARE(2+1)

le compilateur verra ce

(2 + 1) * (2 + 1)

qui se traduira par

9

en outre, voici un exemple complet pour illustrer davantage le point

#include <stdio.h>

#define BAD_SQUARE(x)  x * x 
// In macros alsways srround the variables with parenthesis
#define GOOD_SQUARE(x)  (x) * (x) 

int main(int argc, char const *argv[])
{
    printf("BAD_SQUARE(2) = : %d \n", BAD_SQUARE(2) ); 
    printf("GOOD_SQUARE(2) = : %d \n", GOOD_SQUARE(2) ); 
    printf("BAD_SQUARE(2+1) = : %d ; because the macro will be \
subsituted as 2 + 1 * 2 + 1 \n", BAD_SQUARE(2+1) ); 
    printf("GOOD_SQUARE(2+1) = : %d ; because the macro will be \
subsituted as (2 + 1) * (2 + 1) \n", GOOD_SQUARE(2+1) ); 

    return 0;
}
0
répondu Amjad 2017-01-09 22:08:27

il suffit de mettre entre parenthèses chaque argument de la macro expansion.

#define SQR(x) ((x)*(x))

cela fonctionnera pour n'importe quel argument ou valeur que vous passez.

-2
répondu Nikhil Goyal 2018-02-10 21:02:48