De toute évidence, il y a des moments où #define
les instructions doivent avoir des parenthèses, comme ceci:
#define WIDTH 80+20
int a = WIDTH * 2; // expect a==200 but a==120
Donc, je garde toujours entre parenthèses, même quand ce n'est qu'un seul chiffre:
#define WIDTH (100)
Un nouveau venu sur C m'a demandé pourquoi je fais cela, j'ai donc essayé de trouver un cas Edge où l'absence de parenthèses sur un seul numéro #define
cause des problèmes, mais je n'y pense pas.
Un tel cas existe-t-il?
Oui. L'opérateur de concaténation du 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)
Idem pour la stringisation (#
). Il s'agit clairement d'un cas d'angle et n'a probablement pas d'importance compte tenu de la façon dont WIDTH
sera vraisemblablement utilisé. Pourtant, c'est quelque chose à garder à l'esprit sur le préprocesseur.
(La raison pour laquelle l'ajout du deuxième pingouin échoue est un détail subtil des règles de prétraitement dans C99 - iirc il échoue car il concatène à deux jetons de prétraitement sans espace réservé doit toujours aboutir à un seul jeton de prétraitement - mais cela n'a aucune importance, même si la concaténation était autorisée, elle donnerait toujours un résultat différent de celui du #define
!.
Toutes les autres réponses ne sont correctes que dans la mesure où cela n'a pas d'importance du point de vue du scanner C++ car, en effet, un nombre est atomique. Cependant, à ma lecture de la question, il n'y a aucun signe que seuls les cas sans extension supplémentaire du préprocesseur doivent être pris en compte, donc les autres réponses sont, même si je suis totalement d'accord avec les conseils qui y sont contenus, faux.
Parfois, vous devez écrire du code non pas avec les mises en garde actuelles, mais avec les mises en garde de la prochaine fois que ça va être édité.
À l'heure actuelle, votre macro est un entier unique. Imaginez quelqu'un le modifier à l'avenir. 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 toute modification entre parenthèses.
Ce genre de réflexion 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 composabilité des futures modifications.
Comme Blagovest Buyukliev l'a dit:
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 indivisible atom lors de la lexation et de l'analyse).
Mais je recommanderais les règles suivantes en ce qui concerne les macros:
Si vous souhaitez utiliser des fonctions comme les macros, tenez compte des 2 règles suivantes:
Pourquoi la règle 1.? (Pour garder l'ordre des opérations correct)
#define quad(x) (x*x)
int a = quad(2+3);
s'étendra à:
int a = (2+3*2+3);
Pourquoi la règle 2.? (Pour garantir qu'un effet secondaire n'est appliqué qu'une seule fois)
#define quad(x) (x*x)
int i = 1;
int a = quad(i++);
s'étendra à:
int a = i++ * i++;
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 indivisible atom lors du lexing et de l'analyse.
Puisque 100
est un seul jeton, je doute que vous trouverez un cas d'angle où les parenthèses comptent (pour un seul jeton!)
C'est toujours une bonne habitude OMI, car ils peuvent avoir de l'importance lorsqu'il y a plusieurs jetons impliqués.
Non. Il n'y a aucun cas où #define WIDTH 100
peut donner une expansion non ambiguë ou "surprenante". En effet, cela ne peut entraîner le remplacement d'un seul jeton par un seul jeton.
Comme vous le savez, une confusion de macro se produit lorsqu'un seul jeton (par exemple WIDTH
) entraîne plusieurs jetons (par exemple 80 + 20
). Pour autant que je puisse supposer, c'est la cause seulement pour l'utilisation de parenthèses dans les substitutions et, comme exploré dans mon premier paragraphe, cela ne s'applique pas ici.
Cependant, ce fait technique mis à part, il peut encore s'agir d'une bonne pratique. Il favorise l'habitude et sert également de rappel si cette macro est modifiée à quelque chose de plus complexe.
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 cas suivants:
#define TEMPERATURE1M (-1)
#define TEMPERATURE1P (+1)
Lorsque le code utilise un #define
qui emploie un opérateur, contenant ()
assure les résultats numériques attendus et la priorité.
#define TEMPERATURE_WITH (-1)
#define TEMPERATURE_WITHOUT -1
// Consider how these will compile
int w = 10-TEMPERATURE_WITH;
int wo = 10-TEMPERATURE_WITHOUT; // May not compile
La dernière ligne de code peut compiler étant donné les changements sémantiques C99 @ Olaf
Il y a parfois une bonne raison.
Pour un seul numéro, il n'y a pas de bonne raison.
Pour d'autres cas, comme vous l'avez montré, il y a une bonne raison.
Certaines personnes préfèrent faire très attention et toujours utiliser les parenthèses (@aix le recommande. Je ne le fais pas, mais il n'y a pas de réponse difficile).
Cela ne fera certainement pas de 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.