In den frühen Tagen von C ++, als es auf C geschraubt wurde, konnten Sie NULL nicht so verwenden, wie es definiert wurde (void*)0
. Sie konnten keinem anderen Zeiger als NULL zuweisen void*
, was es irgendwie nutzlos machte. Damals wurde akzeptiert, dass Sie 0
(Null) für Nullzeiger verwendet haben.
Bis heute habe ich weiterhin Null als Nullzeiger verwendet, aber die um mich herum bestehen darauf, sie zu verwenden NULL
. Ich persönlich sehe keinen Vorteil darin, einem NULL
vorhandenen Wert einen Namen ( ) zu geben - und da ich auch gerne Zeiger als Wahrheitswerte teste:
if (p && !q)
do_something();
Dann ist die Verwendung von Null sinnvoller (wie wenn Sie verwenden NULL
, können Sie nicht logisch verwenden p && !q
- Sie müssen explizit mit Null vergleichen NULL
, es sei denn, Sie nehmen an , dass NULL
Null ist. In diesem Fall warum verwenden NULL
).
Gibt es einen objektiven Grund, Null gegenüber NULL zu bevorzugen (oder umgekehrt), oder ist alles nur eine persönliche Präferenz?
Bearbeiten: Ich sollte hinzufügen (und ursprünglich sagen), dass ich mit RAII und Ausnahmen selten Null / NULL-Zeiger verwende, aber manchmal braucht man sie immer noch.
Antworten:
Hier ist Stroustrups Sichtweise: C ++ - FAQ zu Stil und Technik
Das heißt, schwitzen Sie nicht die kleinen Sachen.
quelle
Es gibt einige Argumente (von denen eines relativ neu ist), die meiner Meinung nach Bjarnes Standpunkt dazu widersprechen.
Mit
NULL
ermöglicht Suchanfragen auf seine Verwendung und es zeigt auch , dass der Entwickler wollten ein verwendenNULL
Zeiger, unabhängig davon , ob sie vom Compiler wie interpretiert wirdNULL
oder nicht.Das Beispiel, das jeder zitiert, ist:
Zumindest meiner Meinung nach besteht das Problem mit dem oben Gesagten jedoch nicht darin, dass wir NULL für die Nullzeigerkonstante verwenden, sondern darin, dass wir Überladungen von 'foo' haben, die sehr unterschiedliche Arten von Argumenten annehmen. Der Parameter muss auch ein
int
sein, da jeder andere Typ zu einem mehrdeutigen Aufruf führt und daher eine hilfreiche Compiler-Warnung generiert.Selbst wenn C ++ 0x nicht vorhanden ist, stehen heute Tools zur Verfügung, die überprüfen, ob
NULL
sie für Zeiger und0
für integrale Typen verwendet werden.std::nullptr_t
Typ haben.Dies ist das neueste Argument in der Tabelle. Das Problem von
0
undNULL
wird für C ++ 0x aktiv angegangen, und Sie können garantieren, dass für jede bereitgestellte ImplementierungNULL
das allererste, was sie tun, Folgendes ist:Für diejenigen , die verwendet werden,
NULL
statt0
, wird die Änderung eine Verbesserung der Typsicherheit mit wenig oder gar keine Mühe - wenn alles , was es auch ein paar Fehler fangen können , wo sie verwendet habenNULL
für0
. Für jeden, der0
heute benutzt ... ähm ... hoffentlich haben sie gute Kenntnisse über reguläre Ausdrücke ...quelle
#include
und bleiben auf der sicheren Seite.#define NULL nullptr
scheint gefährlich. Ob gut oder schlecht, viele Legacy-Codes verwenden NULL für andere Dinge als 0. Beispielsweise werden Handles häufig als integraler Typ implementiert, und das Festlegen aufNULL
ist nicht ungewöhnlich. Ich habe sogar Missbräuche wieNULL
das Setzen von achar
auf einen Nullterminator gesehen.NULL
tatsächlich falsch sind. Viele APIs werden seit langemNULL
mit Handles verwendet, und das ist in der Tat die dokumentierte Verwendung mit vielen von ihnen. Es ist nicht pragmatisch, diese plötzlich zu brechen und zu erklären, dass sie es falsch machen.Verwenden Sie NULL. NULL zeigt Ihre Absicht. Dass es 0 ist, ist ein Implementierungsdetail, das keine Rolle spielen sollte.
quelle
Ich benutze immer:
NULL
für Zeiger'\0'
für Zeichen0.0
für Schwimmer und Doppelwo 0 würde gut tun. Es ist eine Frage der Signalabsicht. Das heißt, ich bin nicht anal darüber.
quelle
Ich habe vor langer Zeit aufgehört, NULL zugunsten von 0 zu verwenden (wie auch die meisten anderen Makros). Ich habe dies nicht nur getan, weil ich Makros so weit wie möglich vermeiden wollte, sondern auch, weil NULL in C- und C ++ - Code überstrapaziert zu sein scheint. Es scheint immer dann verwendet zu werden, wenn ein 0-Wert benötigt wird, nicht nur für Zeiger.
Bei neuen Projekten habe ich dies in einen Projektheader eingefügt:
Wenn nun C ++ 0x-kompatible Compiler eintreffen, muss ich nur noch diese Zeile entfernen. Ein netter Vorteil davon ist, dass Visual Studio nullptr bereits als Schlüsselwort erkennt und es entsprechend hervorhebt.
quelle
Die Moral der Geschichte. Sie sollten NULL verwenden, wenn Sie mit Zeigern arbeiten.
1) Es erklärt Ihre Absicht (lassen Sie mich nicht Ihren gesamten Code durchsuchen, um herauszufinden, ob eine Variable ein Zeiger oder ein numerischer Typ ist).
2) In bestimmten API-Aufrufen, die variable Argumente erwarten, verwenden sie einen NULL-Zeiger, um das Ende der Argumentliste anzuzeigen. In diesem Fall kann die Verwendung einer '0' anstelle von NULL zu Problemen führen. Auf einer 64-Bit-Plattform möchte der Aufruf von va_arg einen 64-Bit-Zeiger, Sie übergeben jedoch nur eine 32-Bit-Ganzzahl. Scheint mir, als ob Sie sich darauf verlassen, dass die anderen 32-Bit für Sie auf Null gesetzt werden? Ich habe bestimmte Compiler gesehen (z. B. Intels ICPC), die nicht so freundlich sind - und dies hat zu Laufzeitfehlern geführt.
quelle
NULL
Vielleicht ist es nicht tragbar und nicht sicher. Möglicherweise gibt es noch Plattformen#define NULL 0
(laut Stroustrups FAQ: Soll ich NULL oder 0 verwenden? Zitiert von der obersten Frage und es gehört zu den ersten Suchergebnissen). Zumindest in älteren C ++0
hat eine spezielle konzeptionelle Bedeutung im Zeigerkontext. Sie sollten nicht konkret über Bits nachdenken. Beachten Sie auch , dass in verschiedenen Kontexten integer (short
,int
,long long
) „sizeof(0)
“ anders sein wird. Ich denke, diese Antwort ist ein bisschen falsch.NULL
anstatt(char *)0
,(const char *)0
oder(struct Boo *)0
oder(void *)0
oder was auch immer zum Ausdruck bringt die Absicht deutlicher -. , Ohne (meiner Meinung nach ) zu umständlich)Wenn ich mich richtig erinnere, wird NULL in den von mir verwendeten Headern anders definiert. Für C ist es als (void *) 0 definiert und für C ++ als nur 0. Der Code sah ungefähr so aus:
Persönlich verwende ich immer noch den NULL-Wert, um Nullzeiger darzustellen. Es wird deutlich, dass Sie einen Zeiger anstelle eines integralen Typs verwenden. Ja, intern ist der NULL-Wert immer noch 0, aber er wird nicht als solcher dargestellt.
Außerdem verlasse ich mich nicht auf die automatische Konvertierung von Ganzzahlen in boolesche Werte, sondern vergleiche sie explizit.
Zum Beispiel bevorzugen:
eher, als:
Es genügt zu sagen, dass dies alles in C ++ 11 behoben ist, wo man es einfach
nullptr
anstelle von verwenden kannNULL
, undnullptr_t
das ist auch der Typ von anullptr
.quelle
Ich würde sagen, die Geschichte hat gesprochen und diejenigen, die sich für die Verwendung von 0 (Null) aussprachen, waren falsch (einschließlich Bjarne Stroustrup). Die Argumente für 0 waren hauptsächlich Ästhetik und "persönliche Präferenz".
Nach der Erstellung von C ++ 11 mit seinem neuen Typ nullptr haben einige Compiler (mit Standardparametern) angefangen, sich über die Übergabe von 0 an Funktionen mit Zeigerargumenten zu beschweren, da 0 kein Zeiger ist.
Wenn der Code mit NULL geschrieben worden wäre, hätte eine einfache Suche und Ersetzung über die Codebasis durchgeführt werden können, um ihn stattdessen auf nullptr zu setzen. Wenn Sie mit Code stecken bleiben, der mit der Auswahl von 0 als Zeiger geschrieben wurde, ist es weitaus mühsamer, ihn zu aktualisieren.
Und wenn Sie jetzt neuen Code in den C ++ 03-Standard schreiben müssen (und nullptr nicht verwenden können), sollten Sie wirklich nur NULL verwenden. Dies erleichtert Ihnen die Aktualisierung in Zukunft erheblich.
quelle
Normalerweise verwende ich 0. Ich mag keine Makros und es gibt keine Garantie dafür, dass ein von Ihnen verwendeter Header eines Drittanbieters NULL nicht neu definiert, um etwas Seltsames zu sein.
Sie können ein nullptr-Objekt verwenden, wie von Scott Meyers und anderen vorgeschlagen, bis C ++ ein nullptr-Schlüsselwort erhält:
Google "nullptr" für weitere Informationen.
quelle
(void*)0
wenn sie als C-Code kompiliert wird), fragt nur nach Problemen und sollte nicht verwendet werden.NULL
Over(type *)0
ist die Suchbarkeit, scheint mir. Ansonsten scheint es unnötig zu verschleiern, wenn es kein C-Idiom wäre. Ich persönlich denke, die RedewendungNULL
, sich überall zu verbreiten , verdient es zu sterben.NULL
ist meiner Meinung nach nutzloses Makro. Occams Rasiermesser hat hier etwas zu tun ...Ich habe einmal an einer Maschine gearbeitet, auf der 0 eine gültige Adresse war und NULL als spezieller Oktalwert definiert wurde. Auf diesem Computer (0! = NULL), also Code wie
würde nicht so funktionieren, wie Sie es erwarten. Du musstest schreiben
Obwohl ich glaube, dass die meisten Compiler NULL heutzutage als 0 definieren, erinnere ich mich noch an die Lektion aus jenen Jahren: NULL ist nicht unbedingt 0.
quelle
Ich denke, der Standard garantiert, dass NULL == 0 ist, also können Sie beides tun. Ich bevorzuge NULL, weil es Ihre Absicht dokumentiert.
quelle
foo.bar_ptr = (Bar *) 0
drückt das Sprichwort die Absicht viel klarer aus alsfoo.bar_ptr = NULL
. Diese Angewohnheit ermöglicht es dem Compiler auch, Missverständnisfehler für Sie zu erkennen. Für michfoo.bar_ptr = 0
drückt die Absicht aus und verwendet,NULL
wenn ich weiß, dassfoo.bar_ptr
das ein Zeiger ist.Die Verwendung von 0 oder NULL hat den gleichen Effekt.
Dies bedeutet jedoch nicht, dass beide gute Programmierpraktiken sind. Angesichts der Tatsache, dass es keinen Unterschied in der Leistung gibt, ist die Wahl einer Option mit niedrigem Bewusstsein anstelle einer agnostischen / abstrakten Alternative eine schlechte Programmierpraxis. Helfen Sie den Lesern Ihres Codes, Ihren Denkprozess zu verstehen .
NULL, 0, 0.0, '\ 0', 0x00 und was auch immer übersetzen sich in dasselbe, sind jedoch unterschiedliche logische Einheiten in Ihrem Programm. Sie sollten als solche verwendet werden. NULL ist ein Zeiger, 0 ist eine Menge, 0x0 ist ein Wert, dessen Bits interessant sind usw. Sie würden einem Zeiger nicht '\ 0' zuweisen, unabhängig davon, ob er kompiliert wird oder nicht.
Ich weiß, dass einige Gemeinden dazu ermutigen, fundiertes Wissen über eine Umwelt zu demonstrieren, indem sie die Verträge der Umwelt brechen. Verantwortliche Programmierer erstellen jedoch wartbaren Code und halten solche Praktiken aus ihrem Code heraus.
quelle
Seltsam, niemand, einschließlich Stroustroup, erwähnte das. Während viel über Standards und Ästhetik gesprochen wurde, bemerkte niemand, dass dies der Fall ist gefährlich zu verwenden ,
0
inNULL
‚s statt, zum Beispiel in variable Argumentliste auf der Architektur , wosizeof(int) != sizeof(void*)
. Wie Stroustroup bevorzuge ich0
aus ästhetischen Gründen, aber man muss darauf achten, es nicht dort zu verwenden, wo sein Typ mehrdeutig sein könnte.quelle
0
sofern Sie angeben , welche0
Sie bedeuten - zum Beispiel(int *)0
,(char *)0
,(const char *)0
oder(void *)0
oder(unsigned long long) 0
oder was auch immer. Dies drückt meiner Meinung nach die Absicht viel klarer aus alsNULL
.NULL
steht.(void *)
wenn ich den genauen Typ verwenden könnte. Ich habe absichtlich ein Beispiel für eine (normalerweise) 64-Bit-Ganzzahl in der Liste angegeben, da diese dem Zeiger des Zeigers entspricht. Wenn ich mich daran erinnere, dass älteres C ++NULL
als0
genau definiert wurde (es ist Jahre her, seit ich in C ++ programmiert habe), dann sehen wir keine Verbesserung der Programmkorrektheit. Der neuere C ++ - Standard bietet glücklicherweise einnullptr
Schlüsselwort, sodass wir dieseNULL
Hässlichkeit und die ganze Kontroverse beim Schreiben von neuerem C ++ loswerden können .(void*)
abstrahiertNULL
. UndNULL
drückt die Absicht die meiste Zeit ganz klar aus. Und ich denke, deine Erinnerung ist falsch. Ich bin mir nicht sicher über Standards, aber in der Praxis glaube ich, dass es so war(void*)0
. Und ja, esnullptr
ist ein netter Prettifier, obwohl es sich um dasselbe handeltNULL
- das Angeben eines Nullzeigers ohne Angabe des Typs.nullptr
dieselbe Botschaft trägt wieNULL
, dass es nur darum ging, die Absicht auszudrücken, die Sie am Anfang erwähnt haben. (VorverarbeitungNULL
auf modernengcc
Erträgen__null
, was auch immer es ist).Ich versuche, die ganze Frage zu vermeiden, indem ich nach Möglichkeit C ++ - Referenzen verwende. Eher, als
Sie können oft schreiben
Das funktioniert natürlich nicht immer. Nullzeiger können jedoch überbeansprucht werden.
quelle
Ich bin mit Stroustrup in diesem Fall :-) Da NULL nicht Teil der Sprache ist, bevorzuge ich die Verwendung von 0.
quelle
Meistens persönliche Präferenz, obwohl man argumentieren könnte, dass NULL es ziemlich offensichtlich macht, dass das Objekt ein Zeiger ist, der derzeit auf nichts zeigt, z
IIRC, der Standard verlangt nicht, dass NULL 0 ist, daher ist es wahrscheinlich am besten für Ihren Compiler, die in <stddef.h> definierten Elemente zu verwenden.
Eine weitere Facette des Arguments ist, ob Sie logische Vergleiche (implizite Umwandlung in Bool) oder Explizitätsprüfung gegen NULL verwenden sollten, aber das hängt auch von der Lesbarkeit ab.
quelle
Ich bevorzuge die Verwendung von NULL, da klar ist, dass Ihre Absicht darin besteht, dass der Wert einen Zeiger und keinen arithmetischen Wert darstellt. Die Tatsache, dass es sich um ein Makro handelt, ist bedauerlich, aber da es so tief verwurzelt ist, besteht nur eine geringe Gefahr (es sei denn, jemand tut etwas wirklich ohne Kopf). Ich wünschte, es wäre von Anfang an ein Schlüsselwort, aber was können Sie tun?
Trotzdem habe ich kein Problem damit, Zeiger als Wahrheitswerte an sich zu verwenden. Genau wie bei NULL ist es eine tief verwurzelte Redewendung.
C ++ 09 wird das nullptr-Konstrukt hinzufügen, das meiner Meinung nach längst überfällig ist.
quelle
Ich benutze immer 0. Nicht aus irgendeinem Grund, nur weil ich beim ersten Lernen von C ++ etwas gelesen habe, das die Verwendung von 0 empfohlen hat, und ich habe es einfach immer so gemacht. Theoretisch könnte es ein Verwirrungsproblem bei der Lesbarkeit geben, aber in der Praxis bin ich in Tausenden von Arbeitsstunden und Millionen von Codezeilen noch nie auf ein solches Problem gestoßen. Wie Stroustrup sagt, ist es wirklich nur ein persönliches ästhetisches Problem, bis der Standard nullptr wird.
quelle
Jemand hat es mir einmal gesagt ... Ich werde NULL auf 69 neu definieren. Seitdem benutze ich es nicht mehr: P.
Es macht Ihren Code ziemlich anfällig.
Bearbeiten:
Nicht alles im Standard ist perfekt. Das Makro NULL ist eine implementierungsdefinierte C ++ - Nullzeigerkonstante, die nicht vollständig mit dem C NULL-Makro kompatibel ist. Neben dem impliziten Ausblenden des Typs wird es in ein nutzloses und fehleranfälliges Tool konvertiert.
NULL verhält sich nicht als Nullzeiger, sondern als O / OL-Literal.
Sagen Sie mir, das nächste Beispiel ist nicht verwirrend:
Aus diesem Grund erscheint im neuen Standard std :: nullptr_t
Wenn Sie nicht auf den neuen Standard warten und einen Nullptr verwenden möchten, verwenden Sie mindestens einen anständigen wie den von Meyers vorgeschlagenen (siehe jon.h-Kommentar).
quelle
NULL
ist ein genau definierter Teil des C ++ - Standards. Wenn Sie Personen, die Standardmakros neu definieren möchten, Code in Ihrem Projekt bearbeiten lassen, wird Ihr Code "anfällig". mitNULL
tut nicht.Nun, ich argumentiere dafür, dass ich, wann immer möglich, überhaupt keine 0- oder NULL-Zeiger verwende.
Ihre Verwendung führt früher oder später zu Segmentierungsfehlern in Ihrem Code. Nach meiner Erfahrung ist dies und Zeiger in gereral eine der größten Fehlerquellen in C ++
Außerdem führt dies zu "if-not-null" -Anweisungen im gesamten Code. Viel schöner, wenn Sie sich immer auf einen gültigen Zustand verlassen können.
Es gibt fast immer eine bessere Alternative.
quelle
0
) ist nützlich für das Debuggen. Viel besser, als zufälligen Müll zu dereferenzieren und herauszufinden, wer welches Ergebnis hat.Das Setzen eines Zeigers auf 0 ist einfach nicht so klar. Vor allem, wenn Sie eine andere Sprache als C ++ verwenden. Dies beinhaltet sowohl C als auch Javascript.
Ich habe mich kürzlich mit einem Code wie diesem beschäftigt:
virtual void DrawTo(BITMAP *buffer) =0;
für die reine virtuelle Funktion zum ersten Mal. Ich dachte, es wäre eine Woche lang ein magischer Jiberjash. Als mir klar wurde, dass der Funktionszeiger nur auf a gesetzt wurde
null
(da virtuelle Funktionen in den meisten Fällen nur Funktionszeiger für C ++ sind), habe ich mich selbst getreten.virtual void DrawTo(BITMAP *buffer) =null;
wäre weniger verwirrend gewesen als diese Basterdation ohne den richtigen Abstand zu meinen neuen Augen. Eigentlich frage ich mich, warum C ++ keine Kleinbuchstaben verwendet,
null
so wie es jetzt Kleinbuchstaben falsch und wahr verwendet.quelle