In einer kürzlich durchgeführten Codeüberprüfung versucht ein Mitwirkender zu erzwingen, dass alle NULL
Überprüfungen von Zeigern auf folgende Weise durchgeführt werden:
int * some_ptr;
// ...
if (some_ptr == NULL)
{
// Handle null-pointer error
}
else
{
// Proceed
}
anstatt
int * some_ptr;
// ...
if (some_ptr)
{
// Proceed
}
else
{
// Handle null-pointer error
}
Ich stimme zu, dass sein Weg etwas klarer ist in dem Sinne, dass er explizit "Stellen Sie sicher, dass dieser Zeiger nicht NULL ist" sagt, aber ich würde dem entgegenwirken, indem ich sage, dass jeder, der an diesem Code arbeitet, verstehen würde, dass die Verwendung einer Zeigervariablen in einem if
Anweisung prüft implizit auf NULL
. Ich bin auch der Meinung, dass die zweite Methode eine geringere Chance hat, einen Fehler der Art einzuführen:
if (some_ptr = NULL)
Das ist nur ein absoluter Schmerz zu finden und zu debuggen.
Welchen Weg bevorzugen Sie und warum?
c++
c
if-statement
null
coding-style
Bryan Marble
quelle
quelle
Antworten:
Nach meiner Erfahrung werden Tests der Form
if (ptr)
oderif (!ptr)
bevorzugt. Sie hängen nicht von der Definition des Symbols abNULL
. Sie bieten keine Möglichkeit für die versehentliche Zuordnung. Und sie sind klar und prägnant.Bearbeiten: Wie SoapBox in einem Kommentar hervorhebt, sind sie mit C ++ - Klassen kompatibel, z. B.
auto_ptr
Objekten, die als Zeiger fungieren und eine Konvertierung bereitstellenbool
, um genau diese Redewendung zu aktivieren. Für diese ObjekteNULL
müsste ein expliziter Vergleich mit eine Konvertierung in einen Zeiger aufrufen, der andere semantische Nebenwirkungen haben oder teurer sein kann als die einfache Existenzprüfung, die diebool
Konvertierung impliziert.Ich bevorzuge Code, der sagt, was er ohne nicht benötigten Text bedeutet.
if (ptr != NULL)
hat die gleiche Bedeutung wieif (ptr)
auf Kosten der redundanten Spezifität. Die nächste logische Sache ist zu schreibenif ((ptr != NULL) == TRUE)
und so liegt der Wahnsinn. Die C-Sprache ist klar, dass ein Boolescher Wertif
, der vonwhile
oder dergleichen getestet wurde oder eine spezifische Bedeutung des Werts ungleich Null hat, wahr und Null falsch ist. Redundanz macht es nicht klarer.quelle
int y = *x; if (!x) {...}
in der der Optimierer begründen darf, dass, da*x
undefiniert wäre, wennx
NULL ist, es nicht NULL sein!x
darf und daher FALSE sein muss. Der Ausdruck!ptr
ist kein undefiniertes Verhalten. Wenn im Beispiel der Test vor der Verwendung von durchgeführt*x
würde, wäre der Optimierer falsch, den Test zu eliminieren.if (foo)
ist klar genug. Benutze es.quelle
Ich beginne damit: Konsistenz ist König, die Entscheidung ist weniger wichtig als die Konsistenz in Ihrer Codebasis.
In C ++
NULL ist in C ++ als 0 oder 0L definiert.
Wenn Sie die C ++ - Programmiersprache gelesen haben, schlägt Bjarne Stroustrup vor,
0
dasNULL
Makro bei der Zuweisung explizit zu vermeiden. Ich bin mir nicht sicher, ob er dasselbe mit Vergleichen getan hat. Es ist eine Weile her, seit ich das Buch gelesen habe. Ich glaube, er hat es gerade getanif(some_ptr)
ohne expliziten Vergleich, aber ich bin mir nicht sicher.Der Grund dafür ist, dass das
NULL
Makro täuscht (wie fast alle Makros), es ist tatsächlich0
wörtlich und kein eindeutiger Typ, wie der Name vermuten lässt. Das Vermeiden von Makros ist eine der allgemeinen Richtlinien in C ++. Auf der anderen Seite0
sieht es aus wie eine Ganzzahl und ist es nicht, wenn es mit Zeigern verglichen oder diesen zugewiesen wird. Persönlich könnte ich in beide Richtungen gehen, aber normalerweise überspringe ich den expliziten Vergleich (obwohl einige Leute dies nicht mögen, was wahrscheinlich der Grund ist, warum Sie einen Mitwirkenden haben, der sowieso eine Änderung vorschlägt).Unabhängig von persönlichen Gefühlen ist dies größtenteils eine Wahl des geringsten Übels, da es keine richtige Methode gibt.
Dies ist klar und eine gängige Redewendung, und ich bevorzuge es. Es besteht keine Möglichkeit, dass während des Vergleichs versehentlich ein Wert zugewiesen wird, und es lautet deutlich:
Dies ist klar, wenn Sie wissen, dass
some_ptr
es sich um einen Zeigertyp handelt, aber es kann auch wie ein ganzzahliger Vergleich aussehen:Dies ist klar, in den meisten Fällen macht es Sinn ... Aber es ist eine undichte Abstraktion,
NULL
ist tatsächlich0
wörtlich und könnte leicht missbraucht werden:C ++ 0x hat nullptr, was jetzt die bevorzugte Methode ist, da es explizit und genau ist. Seien Sie nur vorsichtig bei versehentlicher Zuweisung:
Bis Sie in der Lage sind, auf C ++ 0x zu migrieren, ist es meiner Meinung nach Zeitverschwendung, sich Gedanken darüber zu machen, welche dieser Methoden Sie verwenden. Sie sind alle unzureichend, weshalb nullptr erfunden wurde (zusammen mit allgemeinen Programmierproblemen, die zu einer perfekten Weiterleitung führten .) Das Wichtigste ist die Aufrechterhaltung der Konsistenz.
In C.
C ist ein anderes Tier.
In C kann NULL als 0 oder als ((void *) 0) definiert werden, C99 ermöglicht die Implementierung definierter Nullzeigerkonstanten. Es kommt also tatsächlich auf die Definition von NULL durch die Implementierung an, und Sie müssen sie in Ihrer Standardbibliothek überprüfen.
Makros sind sehr verbreitet und werden im Allgemeinen häufig verwendet, um Mängel bei der allgemeinen Programmierunterstützung in der Sprache und anderen Dingen auszugleichen. Die Sprache ist viel einfacher und das Vertrauen in den Vorprozessor häufiger.
Aus dieser Perspektive würde ich wahrscheinlich empfehlen, die
NULL
Makrodefinition in C zu verwenden.quelle
0
in C ++ Recht haben , hat es in C :(void *)0
.0
istNULL
in C ++ vorzuziehen , da Typfehler eine PITA sein können.NULL
trotzdem Null.#define NULL ((void *)0)
vonlinux/stddef.h
NULL
muss aber Null sein.Ich benutze
if (ptr)
, aber das ist es absolut nicht wert, darüber zu streiten.Ich mag meinen Weg, weil er prägnant ist, obwohl andere sagen,
== NULL
dass er leichter zu lesen und expliziter ist. Ich sehe, woher sie kommen, ich bin nur anderer Meinung, dass das zusätzliche Zeug es einfacher macht. (Ich hasse das Makro, also bin ich voreingenommen.) Bis zu dir.Ich bin mit Ihrem Argument nicht einverstanden. Wenn Sie keine Warnungen für Zuweisungen in einer Bedingung erhalten, müssen Sie Ihre Warnstufen erhöhen. So einfach ist das. (Und aus Liebe zu allem, was gut ist, schalten Sie sie nicht um.)
Beachten Sie, dass wir in C ++ 0x etwas tun können
if (ptr == nullptr)
, was für mich besser zu lesen ist. (Wieder hasse ich das Makro. Aber esnullptr
ist nett.) Ich mache esif (ptr)
trotzdem, nur weil es das ist, was ich gewohnt bin.quelle
Ehrlich gesagt verstehe ich nicht, warum es wichtig ist. Entweder ist man ganz klar und jeder, der mäßig Erfahrung mit C oder C ++ hat, sollte beides verstehen. Ein Kommentar:
Wenn Sie den Fehler erkennen und die Funktion nicht weiter ausführen möchten (dh Sie werden sofort eine Ausnahme auslösen oder einen Fehlercode zurückgeben), sollten Sie daraus eine Schutzklausel machen:
Auf diese Weise vermeiden Sie "Pfeilcode".
quelle
if(!p)
ist undefiniertes Verhalten. Es könnte funktionieren oder nicht.if(!p)
ist dies nicht das undefinierte Verhalten, sondern die Zeile davor. Undif(p==NULL)
hätte genau das gleiche Problem.Persönlich habe ich immer verwendet,
if (ptr == NULL)
weil es meine Absicht explizit macht, aber an diesem Punkt ist es nur eine Gewohnheit.Die Verwendung
=
anstelle von==
wird von jedem kompetenten Compiler mit den richtigen Warneinstellungen abgefangen.Der wichtige Punkt ist, einen einheitlichen Stil für Ihre Gruppe auszuwählen und sich daran zu halten. Egal in welche Richtung Sie gehen, Sie werden sich irgendwann daran gewöhnen, und der Verlust an Reibung bei der Arbeit mit dem Code anderer Leute ist willkommen.
quelle
Nur noch ein Punkt zugunsten der
foo == NULL
Praxis: Wennfoo
es sich beispielsweise um einint *
oder ein handeltbool *
, kann dieif (foo)
Prüfung von einem Leser versehentlich so interpretiert werden, dass sie den Wert des Pointees testet, dh alsif (*foo)
. DerNULL
Vergleich hier erinnert daran, dass es sich um einen Zeiger handelt.Aber ich nehme an, eine gute Namenskonvention macht dieses Argument umstritten.
quelle
Eigentlich benutze ich beide Varianten.
Es gibt Situationen, in denen Sie zuerst die Gültigkeit eines Zeigers überprüfen und wenn er NULL ist, kehren Sie einfach zu einer Funktion zurück oder verlassen sie. (Ich weiß, dass dies zu der Diskussion führen kann, "sollte eine Funktion nur einen Austrittspunkt haben")
Meistens überprüfen Sie den Zeiger, tun dann, was Sie wollen, und beheben dann den Fehlerfall. Das Ergebnis kann der hässliche x-mal eingerückte Code mit mehreren ifs sein.
quelle
goto
kann a sehr praktisch sein. Auch in vielen Fällen könnte einemalloc()
, die bereinigt werden müsste, durch eine schnellere ersetzt werdenalloca()
. Ich weiß, dass sie nicht empfohlen werden, aber sie existieren aus einem bestimmten Grund (von mir ist ein gut benanntes Etikett fürgoto
viel sauberer als ein verschleierterif/else
Baum).alloca
ist nicht standardisiert und völlig unsicher. Wenn es fehlschlägt, explodiert Ihr Programm einfach. Es besteht keine Chance auf Wiederherstellung, und da der Stapel relativ klein ist, ist ein Ausfall wahrscheinlich. Bei einem Fehler ist es möglich, dass Sie den Heap überladen und Sicherheitslücken schließen, die die Berechtigung gefährden. Verwendenalloca
oder vlas niemals, es sei denn, Sie haben eine winzige Grenze für die Größe, die zugewiesen werden soll (und dann können Sie genauso gut ein normales Array verwenden).In der Programmiersprache C (K & R) müssen Sie nach null == ptr suchen, um eine versehentliche Zuweisung zu vermeiden.
quelle
if (!valid)
obenif (valid == 0
).Wenn Stil und Format Teil Ihrer Bewertungen sein sollen, sollte es einen vereinbarten Styleguide geben, an dem Sie messen können. Wenn es eine gibt, machen Sie, was der Styleguide sagt. Wenn es keine gibt, sollten Details wie diese so belassen werden, wie sie geschrieben sind. Es ist eine Verschwendung von Zeit und Energie und lenkt davon ab, was Codeüberprüfungen eigentlich aufdecken sollten. Im Ernst, ohne einen Styleguide würde ich grundsätzlich darauf drängen, Code wie diesen NICHT zu ändern, selbst wenn er nicht die von mir bevorzugte Konvention verwendet.
Und nicht, dass es darauf ankommt, aber meine persönliche Präferenz ist
if (ptr)
. Die Bedeutung ist mir sofort klarer als geradeif (ptr == NULL)
.Vielleicht versucht er zu sagen, dass es besser ist, Fehlerbedingungen vor dem glücklichen Weg zu behandeln? In diesem Fall stimme ich dem Rezensenten immer noch nicht zu. Ich weiß nicht, dass es dafür eine akzeptierte Konvention gibt, aber meiner Meinung nach sollte der "normalste" Zustand in jeder if-Aussage an erster Stelle stehen. Auf diese Weise muss ich weniger graben, um herauszufinden, worum es bei der Funktion geht und wie sie funktioniert.
Die Ausnahme ist, wenn der Fehler dazu führt, dass ich von der Funktion zurückkomme oder mich von ihr erholen kann, bevor ich fortfahre. In diesen Fällen behandle ich zuerst den Fehler:
Wenn ich mich vorab mit dem ungewöhnlichen Zustand befasse, kann ich mich darum kümmern und ihn dann vergessen. Aber wenn ich nicht auf dem glücklichen Weg durch den Umgang mit ihm vorne wieder aufstehen, dann sollte es behandelt werden , nachdem dem Hauptfall behandelt werden, da dies den Code verständlicher macht. Meiner Meinung nach.
Aber wenn es nicht in einem Styleguide ist, dann ist es nur meine Meinung, und Ihre Meinung ist genauso gültig. Entweder standardisieren oder nicht. Lassen Sie einen Rezensenten nicht pseudo-standardisieren, nur weil er eine Meinung hat.
quelle
Dies ist eine der Grundlagen beider Sprachen, die Zeiger auf einen Typ und einen Wert auswerten, die
bool
in C ++ undint
C als Steuerausdruck verwendet werden können. Verwenden Sie ihn einfach.quelle
if (foo = bar)
.Deshalb bevorzuge ich
oder
Wenn ich jedoch eine Reihe von Stilrichtlinien schreiben würde, würde ich solche Dinge nicht einfügen, sondern Dinge wie:
quelle
Ich bin ein großer Fan von der Tatsache , dass C / C ++ überprüft nicht , Typen in den Booleschen Bedingungen in
if
,for
undwhile
Aussagen. Ich benutze immer folgendes:auch bei ganzen Zahlen oder anderen Typen, die in bool konvertiert werden:
Codierung in diesem Stil ist für mich lesbarer und klarer. Nur meine persönliche Meinung.
Kürzlich habe ich bei der Arbeit am OKI 431-Mikrocontroller Folgendes festgestellt:
ist effizienter als
weil der Compiler im späteren Fall den Wert von chx mit 1 vergleichen muss. Dabei ist chx nur ein True / False-Flag.
quelle
Die meisten Compiler, die ich verwendet habe, werden zumindest
if
ohne weiteren Syntaxzucker vor der Zuweisung warnen , daher kaufe ich dieses Argument nicht. Das heißt, ich habe beide professionell verwendet und habe auch keine Präferenz für beide. Das== NULL
ist aber meiner Meinung nach definitiv klarer.quelle