Quand peut-on omettre les parenthèses autour des arguments dans les macros?

Souvent et souvent, je sentais que certaines des parenthèses entourant les arguments dans les définitions de macros étaient redondantes. C’est trop gênant de tout mettre entre parenthèses. Si je peux garantir que l’argument n’a pas besoin d’être parenthèses, puis-je omettre les parenthèses? Ou est-ce que leur parenthèse est fortement recommandée?

Je suis venu avec cette question quand j’ai écrit:

#define SWAP_REAL(a, b, temp) do{double temp = a; a = b; b= temp;}while(0) 

Je pense que si un argument apparaît sous la forme d’une valeur l dans la macro, les parenthèses peuvent être omises car cela signifie que l’argument apparaît sans aucune autre opération.

Mon raisonnement est:

  1. La priorité associative des symboles d’assignation est simplement supérieure à celle des virgules.
  2. Vous ne pouvez pas confondre le compilateur en lui faisant croire que votre argument est une expression contenant une virgule. Par exemple, SWAP(a, b, b) ne sera pas interprété correctement comme

     do{double temp = a, b; a, b = b; b= temp;}while(0) 

    qui peut passer la compilation.

Ai-je raison? Quelqu’un peut-il me donner un contre-exemple?

Dans l’exemple suivant,

 #define ADD(a, b) (a += (b)) 

Je pense que l’argument n’est pas nécessairement entre parenthèses. Et dans ce cas particulier, ni l’argument b , non?

@ JaredPar:

  #include  #define ADD(a, b) (a += (b)) int main(){ int a = 0, b = 1; ADD(a; b, 2); return 0; } 

Cela ne peut pas être compilé avec succès sur mon VS2010. Error C2143: syntax error : missing ')' before ';'


En un mot, vous n’avez pas besoin de mettre entre parenthèses les arguments apparaissant comme une valeur L dans la macro, mais il est fortement recommandé de les mettre tous entre parenthèses.

Règles de Macros:

  1. NE PAS faire de macros avec des effets secondaires!
  2. Comme pour les macros sans effet secondaire, il suffit de mettre entre parenthèses tous les arguments sans réfléchir!
  3. Comme pour les macros avec effet secondaire, arrêtez d’être obsessionnel! Entre parenthèses tous! TnT

Il est dangereux de l’omettre si vous utilisez un opérateur qui n’est pas la priorité la plus basse dans votre expression. Je crois que ce serait une virgule.

a op bop est un opérateur tel que + , * etc. sera toujours erroné si a contient une expression de faible priorité telle que 1 || 2 1 || 2

Notez que je ne prétends pas que c’est sans danger dans ces cas. Il existe des moyens plus créatifs pour casser les macros. En passant, n’utilisez pas de macros avec des effets secondaires. Plus généralement, n’utilisez pas de macros en tant que fonctions. (Voir, par exemple, Effective C ++).

Voici un cas où cela fait une différence démontrable

 ADD(x;y, 42) 

Avec entre parenthèses, cela entraîne une erreur de compilation mais sans résultat, un code qui comstack.

 (x;y) += 42; // With parens errors x;y += 42; // Without parens comstacks 

Cela peut sembler un exemple ridicule, mais il est possible de combiner des macros peut facilement conduire à des expressions de code étranges comme ci-dessus.

Pourquoi tenter sa chance ici? C’est juste 2 personnages

Il existe des macros dans lesquelles vous concaténez des éléments pour créer une chaîne (éventuellement à l’aide de l’opérateur # ) ou créez des identificateurs à partir d’arguments de macro à l’aide de l’opérateur ## . Dans ce cas, vous ne parentzez pas les arguments.

De plus, je pense que lorsque les arguments de macro sont eux-mêmes passés en tant qu’arguments de fonction, vous ne devez absolument pas les mettre entre parenthèses:

 #define CALLOC(s, n) calloc(s, n) 

Vous pouvez jouer à des jeux diaboliques en appelant une telle macro ( CALLOC({3, 4}) ), mais vous obtenez ce que vous méritez (une erreur de compilation) – Je ne connais pas de méthode permettant d’appeler cette macro qui fonctionnerait si la macro que vous avez écrite les mêmes arguments qu’un appel direct à calloc() .

Toutefois, si vous utilisez les arguments dans la plupart des expressions arithmétiques, vous devez les envelopper entre parenthèses:

 #define MIN(x, y) (((x) < (y)) ? (x) : (y)) 

Évidemment, si vous l'invoquez avec des arguments avec des effets secondaires, vous obtenez ce que vous obtenez. Mais les arguments ne seront pas mal interprétés comme ils pourraient l'être si vous écriviez:

 #define MIN(x, y) x < y ? x : y 

puis invoqué comme:

 MIN(x = 3 * y + 1, y = 2 * x - 2); 

Le commentaire de Moon suggère une macro SWAP_INT .

Le code suivant utilisant cette macro se comstack proprement lorsqu'il est compilé à l'aide des options par défaut, mais ne parvient pas à se comstackr avec le jeu -DWITH_PARENTHESES .

 #include  #ifdef WITH_PARENTHESES #define SWAP_INT(a, b) do { int temp = (a); (a) = (b); (b) = temp; } while (0) #else #define SWAP_INT(a, b) do { int temp = a; a = b; b = temp; } while (0) #endif int main(void) { int p = 319; int q = 9923; int x = 23; int y = 300; printf("p = %8d, q = %8d, x = %8d, y = %8d\n", p, q, x, y); SWAP_INT(p, q); // OK both ways SWAP_INT(x, y); // OK both ways printf("p = %8d, q = %8d, x = %8d, y = %8d\n", p, q, x, y); SWAP_INT(x /= y, p *= q); // Comstacks without parentheses; fails with them printf("p = %8d, q = %8d, x = %8d, y = %8d\n", p, q, x, y); return 0; } 

Le résultat:

 p = 319, q = 9923, x = 23, y = 300 p = 9923, q = 319, x = 300, y = 23 p = 41150681, q = 13, x = 0, y = 3165437 

Ce n'est pas un moyen sûr ni efficace d'échanger des nombres entiers - la macro sans parenthèses n'est pas une bonne idée.