Existe-t-il une opinion quant à savoir si l'utilisation de #define pour définir des lignes complètes de code pour simplifier le codage est une bonne ou une mauvaise pratique de programmation? Par exemple, si j'avais besoin d'imprimer un tas de mots ensemble, je serais ennuyé de taper
<< " " <<
Pour insérer un espace entre les mots dans une instruction cout. Je pourrais juste faire
#define pSpace << " " <<
et tapez
cout << word1 pSpace word2 << endl;
Pour moi, cela n'ajoute ni ne soustrait à la clarté du code et rend la saisie légèrement plus facile. Il y a d'autres cas où je peux penser où taper sera beaucoup plus facile, généralement pour le débogage.
Des réflexions à ce sujet?
EDIT: Merci pour toutes les bonnes réponses! Cette question m'est venue juste après avoir fait beaucoup de frappe répétitive, mais je n'ai jamais pensé qu'il y aurait d'autres macros moins déroutantes à utiliser. Pour ceux qui ne veulent pas lire toutes les réponses, la meilleure alternative est d'utiliser les macros de votre IDE pour réduire la frappe répétitive.
la source
Réponses:
L'écriture de code est simple. La lecture du code est difficile.
Vous écrivez du code une fois. Il vit depuis des années, les gens le lisent cent fois.
Optimiser le code pour la lecture, pas pour l'écriture.
la source
Personnellement, je déteste ça. Il y a plusieurs raisons pour lesquelles je décourage les gens de cette technique:
Au moment de la compilation, vos modifications de code réelles peuvent être importantes. Le gars suivant arrive et inclut même une parenthèse fermante dans son #define ou un appel de fonction. Ce qui est écrit à un certain point de code est loin de ce qu'il y aura après le prétraitement.
C'est illisible. Il peut être clair pour vous .. pour l'instant .. si c'est juste cette seule définition. Si cela devient une habitude, vous vous retrouverez bientôt avec des dizaines de # définitions et vous commencerez à perdre la trace vous-même. Mais le pire de tout, personne d'autre ne pourra comprendre ce
word1 pSpace word2
que signifie exactement (sans rechercher la #define).Cela peut devenir un problème pour les outils externes. Disons que vous vous retrouvez en quelque sorte avec un #define qui comprend un crochet de fermeture, mais pas de crochet d'ouverture. Tout peut bien fonctionner, mais les éditeurs et autres outils peuvent voir quelque chose comme
function(withSomeCoolDefine;
plutôt particulier (c'est-à-dire qu'ils rapporteront des erreurs et ainsi de suite). (Exemple similaire: un appel de fonction à l'intérieur d'un define - vos outils d'analyse pourront-ils trouver cet appel?)L'entretien devient beaucoup plus difficile. Vous avez tous ceux à définir en plus des problèmes habituels que la maintenance entraîne. En plus du point ci-dessus, la prise en charge des outils de refactorisation peut également être affectée négativement.
la source
Ma pensée principale à ce sujet est que je n'utilise jamais "rendre la frappe plus facile" en règle générale lors de l'écriture de code.
Ma règle principale lors de l'écriture de code est de le rendre facilement lisible. La raison derrière cela est simplement que le code est lu un ordre de grandeur plus de fois qu'il est écrit. En tant que tel, le temps que vous perdez à l' écrire avec soin, de manière ordonnée et correctement disposée est en fait investi dans la poursuite de la lecture et la compréhension beaucoup plus rapidement.
En tant que tel, le #define que vous utilisez rompt simplement la manière habituelle d'alternance
<<
et d' autres choses . Il enfreint la règle de la moindre surprise et n'est pas à mon humble avis une bonne chose.la source
Cette question donne un exemple clair de la façon dont vous pouvez mal utiliser les macros. Pour voir d'autres exemples (et se divertir) voir cette question .
Cela dit, je vais donner des exemples concrets de ce que je considère comme une bonne incorporation des macros.
Le premier exemple apparaît dans CppUnit , qui est un framework de tests unitaires. Comme tout autre framework de test standard, vous créez une classe de test, puis vous devez en quelque sorte spécifier les méthodes à exécuter dans le cadre du test.
Comme vous pouvez le voir, la classe a un bloc de macros comme premier élément. Si j'ai ajouté une nouvelle méthode
testSubtraction
, il est évident ce que vous devez faire pour l'inclure dans le test.Ces blocs de macro s'étendent à quelque chose comme ceci:
Lequel préférez-vous lire et conserver?
Un autre exemple est dans le cadre Microsoft MFC, où vous mappez des fonctions à des messages:
Alors, quelles sont les choses qui distinguent les "bonnes macros" des horribles sortes de mal?
Ils effectuent une tâche qui ne peut être simplifiée autrement. L'écriture d'une macro pour déterminer un maximum entre deux éléments est incorrecte, car vous pouvez obtenir la même chose à l'aide d'une méthode de modèle. Mais il existe des tâches complexes (par exemple, mappage des codes de message aux fonctions membres) que le langage C ++ ne gère tout simplement pas avec élégance.
Ils ont un usage formel extrêmement strict. Dans ces deux exemples, les blocs de macro sont annoncés en démarrant et en terminant les macros, et les macros intermédiaires n'apparaissent que dans ces blocs. Vous avez un C ++ normal, vous vous excusez brièvement avec un bloc de macros, puis vous revenez à la normale. Dans les exemples de "macros diaboliques", les macros sont dispersées dans le code et le malheureux lecteur n'a aucun moyen de savoir quand les règles C ++ s'appliquent et quand elles ne le sont pas.
la source
Il vaudra certainement mieux que vous régliez votre éditeur IDE / texte préféré pour insérer des extraits de code que vous trouvez fastidieux à retaper encore et encore. Et mieux est le terme "poli" pour comparaison. En fait, je ne peux penser à aucun cas similaire lorsque le prétraitement bat les macros de l'éditeur. Eh bien, peut-être un - lorsque, pour des raisons mystérieuses et malheureuses, vous utilisez constamment différents outils de codage. Mais ce n'est pas une justification :)
Cela peut également être une meilleure solution pour des scénarios plus complexes, lorsque le prétraitement de texte peut faire des choses beaucoup plus illisibles et compliquées (pensez à l'entrée paramétrée).
la source
<< " " <<
.Les autres ont déjà expliqué pourquoi vous ne devriez pas le faire. Votre exemple ne mérite évidemment pas d'être implémenté avec une macro. Mais, il existe un large éventail de cas où vous avez utiliser des macros pour des raisons de lisibilité.
Le projet Clang est un exemple notoire d'application judicieuse d'une telle technique : voyez comment les
.def
fichiers y sont utilisés. Avec les macros et#include
vous pouvez fournir une définition unique, parfois entièrement déclarative pour une collection de choses similaires qui seront déroulées dans les déclarations de types, lescase
déclarations le cas échéant, les initialiseurs par défaut, etc. Cela augmente considérablement la maintenabilité: vous n'oublierez jamais d'ajouter de nouveauxcase
par exemple, partout où vous en avez ajouté une nouvelleenum
.Ainsi, comme avec tout autre outil puissant, vous devez utiliser le préprocesseur C avec précaution. Il n'y a pas de règles génériques dans l'art de la programmation, comme "vous ne devriez jamais utiliser ceci" ou "vous devez toujours utiliser cela". Toutes les règles ne sont que des directives.
la source
Il n'est jamais approprié d'utiliser #defines comme ça. Dans votre cas, vous pouvez faire ceci:
la source
Non.
Pour les macros destinées à être utilisées dans le code, une bonne ligne directrice pour tester la pertinence est d'entourer son expansion de parenthèses (pour les expressions) ou d'accolades (pour le code) et de voir si elle sera toujours compilée:
Les macros utilisées dans les déclarations (comme l'exemple dans la réponse d'Andrew Shepherd) peuvent s'en tirer avec un ensemble de règles plus lâches tant qu'elles ne bouleversent pas le contexte environnant (par exemple, basculer entre
public
etprivate
).la source
C'est une chose raisonnablement valable à faire dans un programme "C" pur.
C'est inutile et déroutant dans un programme C ++.
Il existe de nombreuses façons d'éviter la saisie répétitive de code en C ++. En utilisant les fonctionnalités fournies par votre IDE (même avec vi, un simple "
%s/ pspace /<< " " <</g
" économiserait autant de frappe et produirait toujours du code lisible standard). Vous pouvez définir une méthode privée pour l'implémenter ou pour des cas plus complexes, le modèle C ++ serait plus propre et plus simple.la source
En C ++, cela peut être résolu par une surcharge de l'opérateur. Ou même quelque chose d'aussi simple qu'une fonction variadique:
lineWithSpaces(word1, word2, word3, ..., wordn)
est à la fois simple et vous évite de taperpSpaces
encore et encore.Donc, même si dans votre cas cela ne semble pas être un gros problème, il existe une solution plus simple et plus robuste.
En général, il y a peu de cas où l'utilisation d'une macro est beaucoup plus courte sans introduire d'obscurcissement, et la plupart du temps, il existe une solution suffisamment courte utilisant les fonctionnalités du langage réel (les macros étant davantage une simple substitution de chaîne).
la source
Oui, c'est très mauvais. J'ai même vu des gens faire ça:
pour enregistrer la saisie (ce que vous essayez de réaliser).
Un tel code n'appartient qu'à des endroits comme celui-ci .
la source
Les macros sont mauvaises et ne doivent être utilisées que lorsque vous en avez vraiment besoin. Il existe quelques cas où les macros sont applicables (principalement le débogage). Mais en C ++ dans la plupart des cas, vous pouvez utiliser des fonctions en ligne à la place.
la source
goto
, à tous les systèmes de macro possibles, etc.Non, vous n'êtes pas autorisé à utiliser des macros pour enregistrer la saisie .
Cependant, vous êtes autorisé, voire obligé à les utiliser pour séparer la partie non changeante du code des éléments changeants et réduire la redondance. Pour ce dernier, vous devez penser à des alternatives et choisir une macro uniquement si de meilleurs outils ne fonctionnent pas. (Pour la pratique, la macro est tout à fait en fin de ligne, donc l'avoir implique en dernier recours ...)
Pour réduire la saisie, la plupart des éditeurs ont des macros, même des extraits de code intelligents.
la source
switch
/ etc, vous pouvez parier que je vais utiliser des macros pour éviter de devenir fou - et augmenter la lisibilité. L'utilisation de macros pour enregistrer la saisie sur des mots clés, contrôler le flux, etc. est stupide - mais dire que personne ne peut les utiliser pour enregistrer des frappes dans des contextes valides est tout aussi stupide.