Gibt es eine Ansicht darüber, ob die Verwendung von #define zum Definieren vollständiger Codezeilen zur Vereinfachung der Codierung eine gute oder schlechte Programmierpraxis ist? Wenn ich zum Beispiel ein paar Wörter zusammen drucken müsste, würde ich mich über das Tippen ärgern
<< " " <<
Einfügen eines Leerzeichens zwischen Wörtern in einer cout-Anweisung. Ich könnte es einfach tun
#define pSpace << " " <<
und Typ
cout << word1 pSpace word2 << endl;
Für mich addiert oder subtrahiert dies weder die Klarheit des Codes, noch erleichtert es die Eingabe. Es gibt andere Fälle, in denen ich mir vorstellen kann, dass das Tippen viel einfacher ist, normalerweise zum Debuggen.
Irgendwelche Gedanken dazu?
EDIT: Danke für die tollen Antworten! Diese Frage kam mir erst, nachdem ich viel getippt hatte, aber ich hätte nie gedacht, dass es andere, weniger verwirrende Makros geben würde. Für diejenigen, die nicht alle Antworten lesen möchten, ist die beste Alternative, die Makros Ihrer IDE zu verwenden, um sich wiederholende Eingaben zu reduzieren.
quelle
Antworten:
Das Schreiben von Code ist einfach. Das Lesen von Code ist schwierig.
Sie schreiben einmal Code. Es lebt seit Jahren, die Leute lesen es hundertmal.
Optimieren Sie den Code zum Lesen, nicht zum Schreiben.
quelle
Persönlich hasse ich es. Es gibt eine Reihe von Gründen, warum ich Menschen von dieser Technik abhalte:
Während der Kompilierung können Ihre tatsächlichen Codeänderungen erheblich sein. Der nächste Typ kommt und fügt sogar eine schließende Klammer in #define oder einen Funktionsaufruf ein. Was an einem bestimmten Punkt des Codes geschrieben ist, ist weit davon entfernt, was nach der Vorverarbeitung dort sein wird.
Es ist nicht lesbar. Es kann für Sie klar sein .. fürs Erste .. wenn es nur diese eine Definition ist. Wenn es zur Gewohnheit wird, werden Sie bald Dutzende von #Defines haben und beginnen, den Überblick zu verlieren. Aber am schlimmsten ist, dass niemand sonst verstehen kann, was
word1 pSpace word2
genau bedeutet (ohne das #define nachzuschlagen).Dies kann zu einem Problem für externe Tools werden. Angenommen, Sie haben am Ende irgendwie eine #Definition, die eine schließende Klammer, aber keine öffnende Klammer enthält. Alles mag gut funktionieren, aber Editoren und andere Tools mögen das
function(withSomeCoolDefine;
als etwas Besonderes ansehen (dh sie werden Fehler melden und so weiter). (Ähnliches Beispiel: Ein Funktionsaufruf in einem Define. Können Ihre Analysetools diesen Aufruf finden?)Wartung wird viel schwieriger. Sie haben alle diese zusätzlich zu den üblichen Problemen definieren, die die Wartung mit sich bringt. Darüber hinaus kann mit dem obigen Punkt auch die Werkzeugunterstützung für das Refactoring negativ beeinflusst werden.
quelle
Mein Hauptgedanke dabei ist, dass ich beim Schreiben von Code in der Regel niemals "Erleichtern des Tippens" verwende.
Meine Hauptregel beim Schreiben von Code ist, dass er leicht lesbar ist. Das Grundprinzip dahinter ist einfach, dass Code eine Größenordnung öfter gelesen wird, als er geschrieben wurde. Daher wird die Zeit, die Sie verlieren , um es sorgfältig, ordentlich und korrekt zu schreiben, in der Tat investiert, um das Lesen und Verstehen zu beschleunigen.
Als solches unterbricht das von Ihnen verwendete #define einfach die übliche Art von alternierendem
<<
und anderem Zeug . Es verstößt gegen die Regel der geringsten Überraschung und ist meiner Meinung nach keine gute Sache.quelle
Diese Frage gibt ein klares Beispiel dafür, wie Sie Makros schlecht verwenden können. Um andere Beispiele zu sehen (und unterhalten zu werden), sehen Sie sich diese Frage an .
Nachdem ich das gesagt habe, werde ich Beispiele aus der Praxis geben, die meiner Meinung nach eine gute Integration von Makros darstellen.
Das erste Beispiel wird in CppUnit angezeigt , einem Unit-Test-Framework. Wie bei jedem anderen Standard-Testframework erstellen Sie eine Testklasse und müssen dann irgendwie angeben, welche Methoden im Rahmen des Tests ausgeführt werden sollen.
Wie Sie sehen, enthält die Klasse als erstes Element einen Makroblock. Wenn ich eine neue Methode hinzufüge
testSubtraction
, ist es offensichtlich, was Sie tun müssen, um sie in den Testlauf aufzunehmen.Diese Makroblöcke werden folgendermaßen erweitert:
Was würdest DU am liebsten lesen und pflegen?
Ein weiteres Beispiel ist das Microsoft MFC-Framework, in dem Sie Nachrichten Funktionen zuordnen:
Also, was sind die Dinge, die "gute Makros" von der schrecklichen bösen Art unterscheiden?
Sie erfüllen eine Aufgabe, die auf keine andere Weise vereinfacht werden kann. Das Schreiben eines Makros zur Bestimmung eines Maximums zwischen zwei Elementen ist falsch, da Sie dasselbe mit einer Vorlagenmethode erreichen können. Es gibt jedoch einige komplexe Aufgaben (z. B. das Zuordnen von Nachrichtencodes zu Elementfunktionen), die in der C ++ - Sprache nicht elegant ausgeführt werden.
Sie haben eine extrem strenge, formale Verwendung. In beiden Beispielen werden die Makroblöcke durch Starten und Beenden von Makros angekündigt, und die dazwischen liegenden Makros werden immer nur in diesen Blöcken angezeigt. Sie haben normales C ++, entschuldigen sich kurz mit einem Makroblock und kehren dann wieder zum Normalzustand zurück. In den Beispielen für "böse Makros" sind die Makros über den gesamten Code verteilt, und der unglückliche Leser kann nicht wissen, wann die C ++ - Regeln gelten und wann nicht.
quelle
Es ist auf jeden Fall besser, wenn Sie Ihren bevorzugten IDE- / Texteditor für das Einfügen von Codefragmenten optimieren, deren erneute Eingabe Sie als mühsam empfinden. Und besser ist "höfliche" Bezeichnung zum Vergleich. Eigentlich kann ich mir keinen ähnlichen Fall vorstellen, wenn die Vorverarbeitung die Makros des Editors übertrifft. Nun, vielleicht ist es eines - wenn Sie aus mysteriösen und unglücklichen Gründen ständig verschiedene Tools zum Codieren verwenden. Aber es ist keine Rechtfertigung :)
Es kann auch eine bessere Lösung für komplexere Szenarien sein, wenn die Textvorverarbeitung etwas viel Unlesbareres und Komplizierteres bewirken kann (denken Sie an parametrisierte Eingaben).
quelle
<< " " <<
.Die anderen haben bereits erklärt, warum Sie es nicht tun sollten. Ihr Beispiel verdient es offensichtlich nicht, mit einem Makro implementiert zu werden. Aber gibt es eine breite Palette von Fällen , in denen Sie haben Makros für einen aus Gründen der Lesbarkeit zu verwenden.
Ein berüchtigtes Beispiel für eine sinnvolle Anwendung einer solchen Technik ist das Clang- Projekt: Sehen Sie, wie
.def
Dateien dort verwendet werden. Mit Makros und#include
Sie eine einzelne, manchmal vollständig deklarative Definition für eine Sammlung ähnlicher Dinge bereitstellen, die in Typdeklarationen,case
Anweisungen, Standardinitialisierer usw. aufgerollt wird. Dies erhöht die Wartbarkeit erheblich: Sie werden nie vergessen, neue hinzuzufügencase
Anweisungen überall, wenn Sieenum
beispielsweise eine neue hinzugefügt haben .Wie bei jedem anderen leistungsstarken Tool müssen Sie den C-Präprozessor daher sorgfältig verwenden. In der Programmierkunst gibt es keine generischen Regeln, wie "das sollten Sie nie verwenden" oder "das müssen Sie immer verwenden". Alle Regeln sind nur Richtlinien.
quelle
Es ist niemals angebracht, #defines so zu verwenden. In Ihrem Fall könnten Sie dies tun:
quelle
Nein.
Für Makros, die im Code verwendet werden sollen, ist es eine gute Richtlinie zum Testen der Eignung, die Erweiterung mit Klammern (für Ausdrücke) oder geschweiften Klammern (für Code) zu umgeben und zu prüfen, ob sie noch kompiliert werden:
Makros, die in Deklarationen verwendet werden (wie das Beispiel in Andrew Shepherds Antwort), können mit einem lockeren Regelwerk davonkommen, solange sie den umgebenden Kontext nicht stören (z. B. zwischen
public
und wechselnprivate
).quelle
Es ist eine einigermaßen gültige Sache, in einem reinen "C" -Programm zu tun.
Es ist unnötig und verwirrend in einem C ++ - Programm.
Es gibt viele Möglichkeiten, um das wiederholte Eingeben von Code in C ++ zu vermeiden. Durch die Nutzung der von Ihrer IDE bereitgestellten Funktionen (selbst mit vi würde ein einfaches "
%s/ pspace /<< " " <</g
" soviel Tipparbeit sparen und dennoch lesbaren Standardcode erzeugen). Sie könnten eine private Methode definieren, um dies zu implementieren, oder für komplexere Fälle wäre eine C ++ - Vorlage übersichtlicher und einfacher.quelle
In C ++ kann dies durch Überladen von Operatoren behoben werden. Oder auch so etwas Einfaches wie eine variable Funktion:
lineWithSpaces(word1, word2, word3, ..., wordn)
ist sowohl einfach als auch erspart Ihnen das TippenpSpaces
immer wieder zu .In Ihrem Fall scheint das also keine große Sache zu sein, aber es gibt eine einfachere und robustere Lösung.
Im Allgemeinen gibt es nur wenige Fälle, in denen die Verwendung eines Makros ohne Einführung von Verschleierung erheblich kürzer ist, und meistens gibt es eine ausreichend kurze Lösung mit tatsächlichen Sprachfunktionen (Makros sind eher eine bloße Zeichenfolgensubstitution).
quelle
Ja, es ist sehr schlimm. Ich habe sogar Leute gesehen, die das gemacht haben:
Tippen zu speichern (was Sie erreichen wollen).
Ein solcher Code gehört nur an Orten wie diesen .
quelle
Makros sind böse und sollten nur verwendet werden, wenn Sie wirklich müssen. Es gibt einige Fälle, in denen Makros anwendbar sind (hauptsächlich Debugging). In C ++ können Sie jedoch in den meisten Fällen stattdessen Inline- Funktionen verwenden.
quelle
goto
, alle möglichen Makrosysteme usw.Nein, Sie dürfen keine Makros zum Speichern der Eingabe verwenden .
Sie dürfen sie jedoch auch verwenden, um nicht geänderten Code von geänderten zu trennen und die Redundanz zu verringern. Für letztere müssen Sie Alternativen denken und nur dann ein Makro auswählen, wenn bessere Tools nicht funktionieren. (Zum Üben steht das Makro ganz am Ende der Zeile, was bedeutet, dass es das letzte Mittel ist ...)
Um das Tippen zu reduzieren, haben die meisten Editoren Makros, sogar intelligente Code-Schnipsel.
quelle
switch
/ usw. muss, kann man wetten, dass ich Makros verwende, um Wahnsinn zu vermeiden - und die Lesbarkeit zu verbessern. Das Verwenden von Makros zum Speichern der Eingabe von Schlüsselwörtern, Kontrollabläufen und Ähnlichem ist dumm - aber zu sagen, dass niemand sie zum Speichern von Tastenanschlägen in gültigen Kontexten verwenden kann, ist genauso einfach.