it-swarm.com.de

Überprüfung auf NULL-Zeiger in C / C ++

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 von

int * some_ptr;
// ...
if (some_ptr)
{
    // Proceed
}
else
{
    // Handle null-pointer error
}

Ich bin damit einverstanden, dass sein Weg ein wenig klarer ist in dem Sinne, dass explizit gesagt wird: "Stellen Sie sicher, dass dieser Zeiger nicht NULL ist." Die Anweisung if sucht implizit nach NULL. Ich bin auch der Meinung, dass die zweite Methode eine geringere Chance hat, einen Fehler der Sorte einzuführen:

if (some_ptr = NULL)

das ist einfach ein absoluter Schmerz zu finden und zu debuggen.

Welchen Weg bevorzugen Sie und warum?

140
Bryan Marble

Nach meiner Erfahrung werden Tests der Form if (ptr) oder if (!ptr) bevorzugt. Sie hängen nicht von der Definition des Symbols NULL ab. Sie bieten keine Gelegenheit für die zufällige Abtretung. Und sie sind klar und prägnant.

Edit: Wie SoapBox in einem Kommentar hervorhebt, sind sie mit C++ - Klassen wie auto_ptr Kompatibel, die als Zeiger fungieren und eine Konvertierung nach bool ermöglichen. genau diese Redewendung zu ermöglichen. Für diese Objekte müsste ein expliziter Vergleich mit NULL eine Konvertierung in einen Zeiger aufrufen, die andere semantische Nebenwirkungen haben kann oder teurer ist als die einfache Existenzprüfung, die die bool - Konvertierung impliziert.

Ich bevorzuge Code, der sagt, was er ohne unnötigen Text bedeutet. if (ptr != NULL) hat die gleiche Bedeutung wie if (ptr), jedoch auf Kosten redundanter Spezifität. Das nächste logische Ding ist, if ((ptr != NULL) == TRUE) zu schreiben und auf diese Weise liegt der Wahnsinn. Die C-Sprache ist klar, dass ein durch if, while oder dergleichen getesteter Boolescher Wert eine spezifische Bedeutung von Nicht-Null hat, ist wahr und Null ist falsch. Redundanz macht es nicht klarer.

186
RBerteig

if (foo) ist klar genug. Benutze es.

50
wilx

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 Programmiersprache C++ gelesen haben, empfiehlt Bjarne Stroustrup, 0 Explizit zu verwenden, um das NULL Makro bei der Ausführung von Aufgaben , ich bin mir nicht sicher, ob er dasselbe mit Vergleichen gemacht hat. Es ist schon eine Weile her, seit ich das Buch gelesen habe. Ich denke, er hat gerade if(some_ptr) gemacht. ohne einen expliziten Vergleich, aber ich bin verwirrt.

Der Grund dafür ist, dass das Makro NULL irreführend ist (wie fast alle Makros). Es ist tatsächlich ein 0 - Literal, kein eindeutiger Typ, wie der Name vermuten lässt. Das Vermeiden von Makros ist eine der allgemeinen Richtlinien in C++. Andererseits sieht 0 Wie eine Ganzzahl aus und wird nicht mit Zeigern verglichen oder diesen zugewiesen. 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 eine klare und gebräuchliche Redewendung, und ich bevorzuge es, es gibt keine Möglichkeit, versehentlich einen Wert während des Vergleichs zuzuweisen, und es lautet eindeutig:

if(some_ptr){;}

Dies ist klar, wenn Sie wissen, dass some_ptr Ein Zeigertyp ist, es aber auch wie ein Ganzzahlvergleich aussehen kann:

if(some_ptr != 0){;}

Dies ist klar, in den meisten Fällen macht es Sinn ... Aber es ist eine undichte Abstraktion, NULL ist eigentlich 0 Wörtlich und könnte leicht missbraucht werden:

if(some_ptr != NULL){;}

C++ 0x hat nullptr, die jetzt die bevorzugte Methode ist, da sie explizit und genau ist. Achten Sie nur auf versehentliche Zuweisungen:

if(some_ptr != nullptr){;}

Solange Sie nicht in der Lage sind, auf C++ 0x umzusteigen, würde ich behaupten, dass es Zeitverschwendung ist, sich Gedanken darüber zu machen, welche dieser Methoden Sie verwenden. Sie sind alle unzureichend. Aus diesem Grund wurde nullptr erfunden (zusammen mit allgemeinen Programmierproblemen, die zu einer perfekten Weiterleitung führten) .) Das Wichtigste ist, die Konsistenz aufrechtzuerhalten.

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 Nullzeiger-Konstanten. Es kommt also tatsächlich auf die Definition von NULL in der 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 Makrodefinition NULL in C zu verwenden.

24
M2tM

Ich benutze if (ptr), aber darüber lohnt es sich überhaupt nicht zu streiten.

Ich mag meinen Weg, weil er prägnant ist, obwohl andere sagen, dass == NULL Das Lesen einfacher und eindeutiger macht. Ich sehe, wo sie herkommen, ich stimme einfach nicht zu, das zusätzliche Zeug macht es einfacher. (Ich hasse das Makro, also bin ich voreingenommen.) Bis zu Ihnen.

Ich bin mit Ihrer Argumentation nicht einverstanden. Wenn Sie unter bestimmten Bedingungen keine Warnungen für Zuweisungen erhalten, müssen Sie die Warnstufen erhöhen. So einfach ist das. (Und für die Liebe von allem, was gut ist, vertauschen Sie sie nicht.)

Beachten Sie, dass wir in C++ 0x if (ptr == nullptr) ausführen können, was für mich does schöner ist. (Wieder hasse ich das Makro. Aber nullptr ist nett.) Ich mache trotzdem if (ptr), nur weil es das ist, woran ich gewöhnt bin.

19
GManNickG

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 jedoch:

Wenn Sie vorhaben, den Fehler zu erkennen und die Funktion nicht weiter auszuführen (d. H. Sie werden eine Ausnahme auslösen oder sofort einen Fehlercode zurückgeben), sollten Sie eine Schutzklausel daraus machen:

int f(void* p)
{
    if (!p) { return -1; }

    // p is not null
    return 0;
}

Auf diese Weise vermeiden Sie "Pfeilcode".

9
James McNellis

Nur noch ein Punkt für die foo == NULL - Praxis: Wenn foo zum Beispiel ein int * Oder ein bool * Ist, dann ist die if (foo) check kann von einem Leser versehentlich als Test des Spitzenwerts interpretiert werden, dh als if (*foo). Der NULL -Vergleich erinnert daran, dass es sich um einen Zeiger handelt.

Aber ich nehme an, dass eine gute Namenskonvention dieses Argument in Frage stellt.

7

Persönlich habe ich immer if (ptr == NULL) verwendet, weil es meine Absicht explizit macht, aber an diesem Punkt ist es nur eine Gewohnheit.

Mit = anstelle von == wird von jedem kompetenten Compiler mit den richtigen Warnungseinstellungen abgefangen.

Der wichtige Punkt ist, einen einheitlichen Stil für Ihre Gruppe zu wä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 wird willkommen sein.

7
Mark Ransom

Eigentlich verwende ich beide Varianten.

Es gibt Situationen, in denen Sie zuerst die Gültigkeit eines Zeigers prüfen und bei NULL einfach eine Funktion zurückgeben/verlassen. (Ich weiß, dass dies zur Diskussion führen kann, "sollte eine Funktion nur einen Austrittspunkt haben")

Meistens überprüfen Sie den Zeiger, tun dann, was Sie möchten, und beheben dann den Fehlerfall. Das Ergebnis kann der hässliche x-mal eingerückte Code mit mehreren ifs sein.

4
dwo

Die Programmiersprache C (K & R) würde Sie auf null == ptr prüfen lassen, um eine versehentliche Zuweisung zu vermeiden.

4
Derek

Wenn Stil und Format Teil Ihrer Bewertungen sein sollen, sollte es einen vereinbarten Stilleitfaden geben, an dem Sie sich messen können. Wenn es einen gibt, tun 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 ab, welche Code-Reviews wirklich aufgedeckt werden sollten. Im Ernst, ohne einen Styleguide würde ich aus Prinzip dazu drängen, Code wie diesen NICHT zu ändern, auch 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 sogar if (ptr == NULL).

Vielleicht versucht er zu sagen, dass es besser ist, Fehlerzustände vor dem glücklichen Pfad 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 die "normalste" Bedingung in jeder if-Anweisung 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:

if (error_condition)
  bail_or_fix();
  return if not fixed;

// If I'm still here, I'm on the happy path

Wenn ich mich im Vorfeld mit dem ungewöhnlichen Zustand befasse, kann ich mich darum kümmern und es dann vergessen. Aber wenn ich nicht auf den glücklichen Pfad zurückkehren kann, indem ich ihn von vorne anfasse, dann sollte es behandelt werden nach der Hauptfall, weil es den Code verständlicher macht. Meiner Meinung nach.

Aber wenn es nicht in einem Styleguide steht, 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.

3
Darryl

Die meisten Compiler, die ich verwendet habe, warnen zumindest bei der Zuweisung von if ohne weitere Syntax sugar, daher kaufe ich dieses Argument nicht. Das heißt, ich habe beide professionell genutzt und auch keine Präferenz dafür. Das == NULL ist aber meiner Meinung nach definitiv klarer.

1
Michael Dorgan
  • Zeiger sind keine Booleschen Werte
  • Moderne C/C++ - Compiler geben versehentlich eine Warnung aus, wenn Sie if (foo = bar) schreiben.

Deshalb ziehe ich es vor

if (foo == NULL)
{
    // null case
}
else
{
    // non null case
}

oder

if (foo != NULL)
{
    // non null case
}
else
{
    // null case
}

Wenn ich jedoch eine Reihe von Stilrichtlinien schreiben würde, würde ich solche Dinge nicht einfügen, sondern Dinge wie:

Stellen Sie sicher, dass Sie den Zeiger auf Null prüfen.

1
JeremyP

Ich denke das ist ganz klar:

if( !some_ptr )
{
  // handle null-pointer error
}
else
{
  // proceed
}

Lesen Sie es als "Wenn es keinen Zeiger gibt ..."

Darüber hinaus ist es kurz gefasst und birgt keine Gefahr versehentlicher Zuordnungen.

1
sth

Ich bin ein großer Fan der Tatsache, dass C/C++ keine Typen in den Booleschen Bedingungen in if-, for- und while-Anweisungen überprüft. Ich benutze immer folgendes:

if (ptr)

if (!ptr)

sogar für Ganzzahlen oder andere Typen, die in bool konvertiert werden:

while(i--)
{
    // Something to do i times
}

while(cin >> a >> b)
{
    // Do something while you've input
}

Die Codierung in diesem Stil ist für mich lesbarer und klarer. Nur meine persönliche Meinung.

Vor kurzem habe ich bei der Arbeit am OKI 431-Mikrocontroller Folgendes festgestellt:

unsigned char chx;

if (chx) // ...

ist effizienter als

if (chx == 1) // ...

denn in einem späteren Fall muss der Compiler den Wert von chx mit 1 vergleichen. Dabei ist chx nur ein Wahr/Falsch-Flag.

1
Donotalo

Dies ist eine der Grundlagen beider Sprachen, die Zeiger auf einen Typ und einen Wert auswerten, der als Steuerausdruck verwendet werden kann, bool in C++ und int in C. Verwenden Sie ihn einfach.

1
Jens Gustedt