Y a-t-il une bonne raison de toujours inclure une définition entre parenthèses dans C?

Clairement, il y a des moments où define s doit avoir des parenthèses, comme ceci:

 #define WIDTH 80+20 int a = WIDTH * 2; //expect a==200 but a==120 

J’ai donc toujours mis entre parenthèses, même si ce n’est qu’un seul numéro:

 #define WIDTH (100) 

Quelqu’un de nouveau sur C m’a demandé pourquoi je faisais cela, alors j’ai essayé de trouver un cas extrême où l’absence de parenthèses sur un seul numéro define problèmes, mais je ne peux pas en penser.

Un tel cas existe-t-il?

Oui L’opérateur de concaténation de préprocesseur ( ## ) provoquera des problèmes, par exemple:

 #define _add_penguin(a) penguin ## a #define add_penguin(a) _add_penguin(a) #define WIDTH (100) #define HEIGHT 200 add_penguin(HEIGHT) // expands to penguin200 add_penguin(WIDTH) // error, cannot concatenate penguin and (100) 

Même chose pour la chaîne ( # ). Clairement, il s’agit d’un cas particulier et cela n’a probablement pas d’importance compte tenu de la façon dont WIDTH sera vraisemblablement utilisé. Cependant, il faut garder à l’esprit le préprocesseur.

(La raison pour laquelle l’ajout du second pingouin échoue est un détail subtil des règles de prétraitement dans C99 – iirc parce qu’il échoue car la concaténation en deux jetons de prétraitement non-placeholder doit toujours aboutir à un seul jeton de prétraitement a été autorisé, il donnerait toujours un résultat différent de la #define crochets!).

Toutes les autres réponses ne sont correctes que dans la mesure où cela n’a pas d’importance du sharepoint vue du scanner C ++ car, en effet, un nombre est atomique. Cependant, à ma lecture de la question, il n’ya aucun signe que seuls les cas sans extension de préprocesseur devraient être pris en compte, alors les autres réponses sont erronées, même si je suis tout à fait d’accord avec les conseils qui y figurent.

Parfois, vous devez écrire du code sans tenir compte des avertissements actuels, mais avec les mises en garde de la prochaine modification .

Actuellement, votre macro est un entier unique. Imaginez que quelqu’un l’édite dans le futur. Disons qu’ils ne sont pas vous, mais quelqu’un qui est moins prudent ou plus pressé. La parenthèse est là pour leur rappeler de mettre des modifications entre parenthèses.

Ce type de reflection est une bonne habitude en C. J’écris personnellement du code dans un style que certaines personnes pourraient trouver “redondant”, avec des choses comme ça, mais surtout en ce qui concerne la gestion des erreurs. La redondance concerne la maintenabilité et la composition des éditions futures.

Chaque fois que la définition consiste en un seul jeton (un seul opérande, aucun opérateur), les parenthèses ne sont pas nécessaires car un seul jeton (tel que 100 ) est un atome indivisible lors de la lexage et de l’parsing.

Comme l’a dit Blagovest Buyukliev :

La définition consiste en un seul jeton (un seul opérande, aucun opérateur), les parenthèses ne sont pas nécessaires car un seul jeton (tel que 100) est un atome indivisible lors de la lexage et de l’parsing.

Mais je recommanderais les règles suivantes en ce qui concerne les macros:

  1. Évitez de fonctionner comme les macros @ voir le commentaire de Lundin.

Si vous voulez utiliser une fonction comme les macros, considérez mal les deux règles suivantes:

  1. Toujours utiliser des crochets pour les arguments dans les macros
  2. N’utiliser qu’un argument de macro une fois

Pourquoi la règle 1.? (Pour garder l’ordre des opérations correct)

 #define quad(x) (x*x) int a = quad(2+3); 

étendra à:

 int a = (2+3*2+3); 

Pourquoi la règle 2.? (Pour vous assurer qu’un effet secondaire n’est appliqué qu’une seule fois)

 #define quad(x) (x*x) int i = 1; int a = quad(i++); 

étendra à:

 int a = i++ * i++; 

Puisque 100 est un jeton unique, je doute que vous trouviez un cas en coin où les parenthèses sont importantes (pour un seul jeton!)

C’est toujours une bonne habitude, car ils peuvent avoir de l’importance lorsque plusieurs jetons sont impliqués.

Non, il n’y a pas de cas où #define WIDTH 100 peut produire une expansion sans ambiguïté ou “surprenante”. Cela est dû au fait qu’un seul jeton peut être remplacé par un seul jeton.

Comme vous le savez, une confusion macroéconomique s’ensuit quand un seul jeton (par exemple, WIDTH ) produit plusieurs jetons (par exemple, 80 + 20 ). Autant que je puisse le supposer, c’est la seule cause de l’utilisation des parenthèses dans les substitutions et, comme expliqué dans mon premier paragraphe, cela ne s’applique pas ici.

Cependant, mis à part ce fait technique, cela peut encore être une bonne pratique. Cela favorise l’habitude, et il sert également de rappel si cette macro est modifiée pour devenir quelque chose de plus complexe.

Il y a une bonne raison, parfois.

Pour un numéro unique, il n’y a pas de bonne raison.

Pour d’autres cas, comme vous vous êtes montré, il y a une bonne raison.

Certaines personnes préfèrent être très prudentes et utiliser toujours les parenthèses (@aix le recommande. Je ne le fais pas, mais il n’y a pas de réponse définitive).

Cela ne fera certainement pas mal et c’est une bonne habitude. Mais il n’y a pas de différence entre (100) et 100 pour les calculs numériques.

Lorsque le code ne définit qu’un nombre, @Alexander Gessler répond bien à la question.

Pourtant, de nombreux codeurs ne remarquent pas les opérateurs unaires dans les domaines suivants:

 #define TEMPERATURE1M (-1) #define TEMPERATURE1P (+1) 

Lorsque le code utilise un #define utilisant un opérateur, enclosing () assure les résultats numériques attendus et la priorité.

 #define TEMPERATURE_WITH (-1) #define TEMPERATURE_WITHOUT -1 // Consider how these will comstack int w = 10-TEMPERATURE_WITH; int wo = 10-TEMPERATURE_WITHOUT; // May not comstack 

La dernière ligne de code peut comstackr avec les changements sémantiques C99 @Olaf