Ist NULL immer falsch?

Lesezeit: 8 Minuten

Benutzeravatar von Sydius
Sydius

Kann man davon ausgehen NULL wird in C immer in false übersetzt?

void *somePtr = NULL;

if (!somePtr) {
  /* This will always be executed? */
}

Oder sollte eine explizite Prüfung gegen den Wert von erfolgen NULL gemacht sein?

  • Ich verweise einfach auf Frage 5.3 der C-FAQ. Es beantwortet genau diese Frage.

    anon

    20. Januar 2009 um 3:33 Uhr

  • Ihr Code verwendet den Wert nicht, wenn NULL

    – Johannes Schaub – litb

    7. Dezember 2011 um 16:11 Uhr

  • if (NULL) ist ein direkter Test von NULL. if (!somePtr) ist nicht.

    – chux – Wiedereinsetzung von Monica

    1. Dezember 2021 um 2:03 Uhr

Benutzeravatar von tvanfosson
tvanfosson

Ja. NULL wird als falsch ausgewertet, da C jeden Nicht-Null-Wert als wahr und jeden Null-Wert als falsch betrachtet. NULL ist im Wesentlichen die zero Adresse und wird in Vergleichen als solche behandelt, und ich glaube, sie würde für die boolesche Prüfung zu einem Int befördert werden. Ich würde erwarten, dass Ihr Code für jeden lesbar ist, der mit C vertraut ist, obwohl ich die Überprüfung wahrscheinlich explizit machen würde.

In der C- und C++-Programmierung werden zwei Nullzeiger garantiert gleich verglichen; ANSI C garantiert, dass jeder Nullzeiger bei einem Vergleich mit einem Integer-Typ gleich 0 ist; Darüber hinaus ist das Makro NULL als Nullzeigerkonstante definiert, dh als Wert 0 (entweder als ganzzahliger Typ oder in einen Zeiger auf void konvertiert), sodass ein Nullzeiger mit NULL verglichen wird.

Ref: http://en.wikipedia.org/wiki/Null_pointer#Null_pointer

  • Eine explizite Überprüfung mag in einigen Fällen eindeutiger sein, aber dies ist ein C-Idiom, dessen Gültigkeit von der Sprache garantiert wird. 🙂

    – Gregor D

    20. Januar 2009 um 1:01 Uhr

  • Ich hätte geweint, wenn mein ganzer C-Code, der diese if-Zeugs verwendet, jetzt ungültig wäre 🙂

    – Johannes Schaub – litb

    20. Januar 2009 um 1:06 Uhr

  • Sie werfen jedoch nicht int. Sie vergleichen 0 mit dem Zeiger. 0 ist eine Nullzeigerkonstante. und wenn Sie eine Nullzeigerkonstante mit einem Zeiger vergleichen, wird die Nullzeigerkonstante zu einem Nullzeiger des richtigen Typs. und ein Nullzeiger vergleicht ungleich mit jedem gültigen Zeiger. das will er

    – Johannes Schaub – litb

    20. Januar 2009 um 1:14 Uhr

  • ja jpalecek, das ist der springende Punkt. ein “Nullzeiger” bedeutet nicht “Nullbits”. Ein Nullzeiger ist eine Blackbox. In if ist das „!= 0“ implizit, und in !ptr ist das „== 0“ implizit. Wenn Sie also if(ptr) ausführen, wird der Zeiger mit einer Nullzeigerkonstante verglichen.

    – Johannes Schaub – litb

    20. Januar 2009 um 1:21 Uhr

  • NULL is essentially the zero address das ist nicht ganz richtig. NULL ist 0, wenn es in einen numerischen Wert konvertiert wird, aber der Wert des Nullzeigers kann ungleich Null sein. Ist NULL in C immer Null?. Die Adresse 0 kann gültig sein, insb. auf eingebetteten Systemen

    – phuklv

    30. November 2019 um 6:02 Uhr


Benutzeravatar von Hans Passant
Hans Passanten

Die ‘C’-Sprache stammt aus einer Zeit, in der (void*)0 tatsächlich ein gültiger Zeiger sein könnte. Vor nicht allzu langer Zeit hatten die 8080- und Z80-Mikroprozessoren einen Interrupt-Vektor an der Adresse 0. Angesichts solcher Architekturentscheidungen konnte er nichts anderes tun, als eine Header-Datei den Wert NULL deklarieren zu lassen. Es gab einige längst vergessene Compiler, bei denen NULL nicht gleich (void*)0 war (0xffff war die nächste Alternative), wodurch Ihre if()-Anweisung ein undefiniertes Verhalten erhielt.

C++ hat dem gnädigerweise ein Ende gesetzt, ein Nullzeiger ist von 0 zuweisbar und gegen 0 testbar.

  • MMUs waren bei der Änderung wahrscheinlich bedeutender als C++.

    – Jonathan Leffler

    20. Januar 2009 um 1:00 Uhr

  • Zu Ihrem C++-Satz: Das ist falsch. 0 ist kein Nullzeiger. 0 ist eine Nullzeigerkonstante. nichtig * p = 0; jetzt ist p ein Nullzeiger. Es ist ein Unterschied, weil ein Nullzeiger einen Zeigertyp hat, während eine Nullzeigerkonstante einen ganzzahligen Typ hat und ein konstanter Ausdruck ist

    – Johannes Schaub – litb

    20. Januar 2009 um 1:03 Uhr

  • C99 garantiert, dass eine 0, die in einen Zeigertyp umgewandelt wird, auch ein Nullzeiger ist – ich habe mir nie die Mühe gemacht, frühere Standards zu lesen, also keine Ahnung, wann das passiert ist …

    – Christoph

    20. Januar 2009 um 1:03 Uhr

  • “Ihrer if () -Anweisung ein undefiniertes Verhalten geben.”C FAQ widerspricht

    – jfs

    16. Juni 2016 um 15:50 Uhr


  • 0 bleibt immer noch eine vollkommen gültige Adresse auf jedem Bogen, für den ich MMU-Code geschrieben habe. Es ist nur eine Konvention vieler C-Laufzeiten, die seine Verwendung ungültig machen. In modernem Linux können Sie als Root ein Objekt mit MAP_FIXED auf 0 mmabbilden. In Unix vor nicht allzu langer Zeit war es üblich, eine schreibgeschützte Nullseite auf Null abzubilden, damit strcmp(NULL, …) keinen Fehler verursachte, sondern nur auf eine leere Zeichenkette passte.

    – trifft sich

    25. November 2019 um 20:23 Uhr

Es ist nie sicher, etwas anzunehmen.

Eine explizite Überprüfung ist auch klarer darüber, was Sie testen.

  • Früher sind wir noch einen Schritt weiter gegangen und haben einen typspezifischen Nullwert für jedes unserer typdefinierten Elemente definiert: Structs, Int, Longs, was auch immer. Auf diese Weise würde die Bedingung “if (foo != fooNil) { etc. }” lauten. Haftungsausschluss: Ich habe früher für Simonyi bei Xerox gearbeitet, also war mein Gehirn kontaminiert.

    – Peter Rowwell

    20. Januar 2009 um 0:52 Uhr

  • @Peter Rowell: Ich habe ziemlich lange #define NIL(x) ((x)0) verwendet, um ungefähr diesen Effekt zu erzielen: NIL(foo), NIL(char *), NIL(bar) usw.

    – Jonathan Leffler

    20. Januar 2009 um 1:02 Uhr

  • @Jonathan: in welcher Sprache – C oder C++? In C99 ist das unnötig, denn „Zwei Nullzeiger müssen gleich verglichen werden“.

    – Christoph

    20. Januar 2009 um 1:05 Uhr

Benutzeravatar von Captain Segfault
Kapitän Segfault

Ja (zumindest für jeden standardkonformen C-Compiler!)

Von dem comp.lang.c FAQ:

F: Ist der abgekürzte Zeigervergleich “if(p)” zum Testen auf Nicht-Null-Zeiger gültig? Was ist, wenn die interne Darstellung für Nullzeiger nicht Null ist?

A: Es ist immer gültig.

Benutzeravatar von Ralph
Ralf

Meine Kopie von ISO/IEC 9899:TC3 (Committee Draft – 7. September 2007) sagt:

6.3 Konvertierungen

1 Mehrere Operatoren wandeln Operandenwerte automatisch von einem Typ in einen anderen um.

6.3.2.3 Zeiger

3 Ein ganzzahliger konstanter Ausdruck mit dem Wert 0 […] wird als Nullzeigerkonstante bezeichnet. Wenn eine Nullzeigerkonstante in einen Zeigertyp konvertiert wird, ist der resultierende Zeiger, der als Nullzeiger bezeichnet wird, garantiert ungleich mit einem Zeiger auf ein Objekt oder eine Funktion.

Bis jetzt, ptr!=0 ist wahr (1) für alle Nicht-Null ptraber es ist noch offen, wie sich zwei Nullzeiger vergleichen.

6.5.9 Gleichheitsoperatoren

5 […] Wenn ein Operand ein Zeiger und der andere eine Nullzeigerkonstante ist, wird die Nullzeigerkonstante in den Typ des Zeigers konvertiert.

6 Zwei Zeiger sind genau dann gleich, wenn beide Nullzeiger sind […]

Somit, ptr==0 ist 1 (und ptr!=0 0 ist), genau dann, wenn ptr ist ein Nullzeiger.

6.5.3.3 Unäre arithmetische Operatoren

5 Das Ergebnis des logischen Negationsoperators ! ist 0, wenn der Wert seines Operanden ungleich 0 ist, 1, wenn der Wert seines Operanden gleich 0 ist. Das Ergebnis hat den Typ int. Der Ausdruck !E entspricht (0==E).

Dasselbe gilt also für !ptr.

6.8.4.1 Die if-Anweisung

1 Der steuernde Ausdruck einer if-Anweisung muss einen Skalartyp haben.

2 In beiden Formen wird die erste Unteranweisung ausgeführt, wenn der Ausdruck ungleich 0 ist.

Beachten Sie, dass a skalarer Typ ist ein arithmetischer Typ oder ein Zeigertyp (siehe „6.2.5 Typen“, Abschnitt 21). Zusammengenommen haben wir:

  • if (ptr) gelingt ⇔ ptr!=0 ist 1 ⇔ ptr ist kein Nullzeiger.
  • if (!ptr) gelingt ⇔ ptr==0 ist 1 ⇔ ptr ist ein Nullzeiger.

Ja, if(!p) gültig ist und garantiert funktioniert.

Ein ganzzahliger konstanter Ausdruck mit dem Wert 0 oder ein solcher Ausdruck, der in den Typ void * umgewandelt wird, wird als Nullzeigerkonstante bezeichnet. Wenn eine Nullzeigerkonstante in einen Zeigertyp konvertiert wird, ist der resultierende Zeiger, der als Nullzeiger bezeichnet wird, garantiert ungleich mit einem Zeiger auf ein Objekt oder eine Funktion.

https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p3

Das bedeutet, dass (void*)0 ist ein Nullzeiger. Es bedeutet auch, dass wenn p ist dann ein Zeiger p==0 ist äquivalent zu p==(void*)0.

Es bedeutet auch, dass wenn p ist also kein Nullzeiger p==(void*)0 wird zu bewerten 0.

So weit, ist es gut.

Die Konvertierung eines Nullzeigers in einen anderen Zeigertyp ergibt einen Nullzeiger dieses Typs. Beliebige zwei Nullzeiger sind gleich zu vergleichen.

http://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p4

Beachten Sie, dass “Beliebige zwei Nullzeiger sind gleich zu vergleichen.” Das bedeutet, wenn p ist dann ein Nullzeiger p==0 wird als wahr bewertet, weil 0 werden befördert (void*)0 was ein Nullzeiger ist. Es bedeutet auch, dass kein Nicht-Null-Zeiger gleich einem Null-Zeiger sein kann.

Schauen wir uns den Negationsoperator an.

Das Ergebnis des logischen Negationsoperators ! ist 0, wenn der Wert seines Operanden ungleich 0 ist, 1, wenn der Wert seines Operanden gleich 0 ist. Das Ergebnis hat den Typ int. Der Ausdruck !E entspricht (0==E).

http://port70.net/~nsz/c/c11/n1570.html#6.5.3.3p5

Das sagt uns das !p ist das gleiche wie p==0 per Definition, was dasselbe ist wie p==(void*)0 wie oben erwähnt.

Und unter Berücksichtigung der Tatsache, dass alle Nullzeiger gleich sind, bedeutet dies Folgendes p==(void*)0 kann nur als wahr ausgewertet werden, wenn p ist ein Nullzeiger und nur dann falsch, wenn p ist kein Nullzeiger.

Also ja, if(!p) ist ein absolut sicherer Weg, um zu überprüfen, ob p ein Nullzeiger ist oder nicht.

NULL ist nur eine Präprozessordefinition. Es ist in stdio.h. Normalerweise würde nur eine verrückte Person es neu definieren, aber es ist möglich. Ein Beispiel:

#include <stdio.h>
#ifdef NULL
#undef NULL
#endif
#define NULL 1

void main()
{

        if (NULL)
                printf("NULL is true\n");
        else
                printf("NULL is false\n");
}

Dieser Code gibt “NULL ist wahr” aus. Probieren Sie es aus, wenn Sie mir nicht glauben. Ihr Compiler warnt Sie möglicherweise nicht einmal, dass Sie etwas Seltsames tun.

  • Aber wenn Sie NULL auf 1 definieren und somePtr = NULL zuweisen, erhalten Sie zumindest eine Warnung, dass Sie eine Ganzzahl in einen Zeiger umwandeln.

    – Markus James

    20. Januar 2009 um 6:11 Uhr

  • Interessant. Sie können dafür sorgen, dass es nicht warnt, indem Sie Folgendes tun: #define NULL (void *) 1

    – Blödeln

    21. Januar 2009 um 0:10 Uhr

  • Das wäre schlichtweg falsch. Der Compiler und die C-Standardbibliothek sind aus einem bestimmten Grund zusammen gebündelt. Wenn Sie damit herumspielen, brechen Sie das.

    – Spidy

    30. November 2012 um 12:11 Uhr

1417900cookie-checkIst NULL immer falsch?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy