Ich habe C ++ für weniger als ein Jahr entwickelt, aber in dieser Zeit habe ich mehrere Leute darüber reden hören, wie schrecklich #define
ist. Jetzt merke ich, dass es vom Präprozessor statt vom Compiler interpretiert wird und somit nicht debuggt werden kann, aber ist das wirklich so schlimm?
Hier ist ein Beispiel (ungeprüfter Code, aber Sie erhalten die allgemeine Idee):
%Vor%#define
? Warum ist dieser Code schlecht?
Weil VERSION überschrieben werden kann und der Compiler es nicht sagt.
%Vor%Gibt es eine Alternative zur Verwendung von #define?
oder
%Vor%Das eigentliche Problem ist, dass Defines von einem anderen Werkzeug als dem Rest der Sprache (dem Präprozessor) gehandhabt werden. Daher weiß der Compiler nichts davon und kann Ihnen nicht helfen, wenn etwas schief geht - wie die Wiederverwendung eines Präprozessornamens.
Betrachten wir den Fall von max
, der manchmal als Makro implementiert wird. Daher können Sie den Bezeichner max
nirgendwo in Ihrem Code verwenden. Irgendwo . Aber der Compiler wird es dir nicht sagen. Stattdessen wird Ihr Code schrecklich schief gehen und Sie haben keine Ahnung warum.
Nun, mit einiger Vorsicht kann dieses Problem minimiert (wenn nicht vollständig beseitigt) werden. Aber für die meisten Anwendungen von #define
gibt es sowieso bessere Alternativen, so dass die Kosten-Nutzen-Rechnung verzerrt wird: ein geringer Nachteil für den no Nutzen überhaupt. Warum ein defektes Feature verwenden, wenn es keinen Vorteil bietet?
Also hier ist ein sehr einfaches Diagramm:
Es "richtig" zu machen ist eine Kunst für sich, aber es gibt ein paar einfache Richtlinien:
Verwenden Sie einen eindeutigen Namen. Alle Großbuchstaben, immer mit einem eindeutigen Bibliotheksbezeichner. %Code%? Aus. %Code%? Aus. Verwenden Sie stattdessen max
und VERSION
. Zum Beispiel verwenden Boost-Bibliotheken, große Benutzer von Makros, immer Makros, die mit MY_COOL_LIBRARY_MAX
beginnen.
Vorsicht vor der Auswertung. In der Tat ist ein Parameter in einem Makro nur Text, der ersetzt wird. Als Konsequenz wird MY_COOL_LIBRARY_VERSION
gebrochen: Es könnte als BOOST_<LIBRARY_NAME>_
verwendet werden, was zu #define MY_LIB_MULTIPLY(x) x * x
führt. Nicht was wir wollten. Um dagegen zu wehren, immer parenhesiere alle Verwendungen der Argumente (es sei denn, du weißt genau was du tust - Spoiler: du wahrscheinlich nicht t, sogar Experten bekommen dies oft alarmierend oft).
Die richtige Version dieses Makros wäre:
%Vor%Aber es gibt immer noch viele Möglichkeiten, Makros fürchterlich falsch zu machen, und, um es noch einmal zu sagen, der Compiler wird dir hier nicht helfen.
#define
ist nicht von Natur aus schlecht, es ist einfach zu missbrauchen. Für etwas wie eine Versionszeichenkette funktioniert es gut, obwohl ein const char*
besser wäre, aber viele Programmierer verwenden es für viel mehr als das. Die Verwendung von #define
als typedef ist zum Beispiel dumm, wenn in den meisten Fällen ein typedef besser wäre. Es ist also nichts falsch mit #define
-Anweisungen, und einige Dinge können nicht ohne sie gemacht werden. Sie müssen von Fall zu Fall bewertet werden. Wenn Sie einen Weg finden, um ein Problem zu lösen, ohne den Präprozessor zu verwenden, sollten Sie es tun.
Ich würde #define
nicht verwenden, um eine Konstante zu definieren, die static
oder noch besser verwendet
%Code%
%Code%
ODER
const int kMajorVer = 1;
Herb sutter hat hier einen exzellenten Artikel, der ausführlich erklärt, warum const int kMinorVer = 2;
schlecht ist, und listet einige Beispiele auf, wo es eigentlich keinen anderen Weg gibt, um dasselbe zu erreichen: Ссылка .
Grundsätzlich wie bei vielen Dingen ist es in Ordnung, solange Sie es richtig verwenden, aber es ist leicht zu missbrauchen und Makrofehler sind besonders kryptisch und ein Bugger zum Debuggen.
Ich persönlich benutze sie für bedingten Debug-Code und auch Variant Datendarstellungen, die am Ende des Artikels sutter detailliert aufgeführt ist.
Im Allgemeinen ist der Präprozessor schlecht, weil er einen Zwei-Pass-Kompilierungsprozess erzeugt, der unsicher ist, schwer zu decodierende Fehlermeldungen erzeugt und zu schwer lesbarem Code führen kann. Sie sollten es nicht verwenden, wenn möglich:
%Vor%Es gibt jedoch Fälle, in denen es unmöglich ist, das zu tun, was Sie ohne den Präprozessor machen wollen:
%Vor%Tags und Links c++ coding-style global-variables c-preprocessor