Was ist der Unterschied zwischen NULL, '\0' und 0

In C scheint es Unterschiede zwischen verschiedenen Werten von Null zu geben - NULL, NUL und 0.

Ich weiß, dass das ASCII-Zeichen '0' zu 48 oder 0x30 ausgewertet wird.

Der NULL-Zeiger ist normalerweise definiert als:

#define NULL 0

Oder

#define NULL (void *)0

Außerdem gibt es das NUL-Zeichen '\0', das anscheinend ebenfalls zu 0 ausgewertet wird.

Gibt es Fälle, in denen diese drei Werte nicht gleich sein können?

Gilt dies auch für 64-Bit-Systeme?

Lösung

Anmerkung: Diese Antwort gilt für die Sprache C, nicht für C++.


Null-Zeiger

Das Integer-Konstanten-Literal "0" hat je nach Kontext, in dem es verwendet wird, unterschiedliche Bedeutungen. In allen Fällen handelt es sich immer noch um eine Integer-Konstante mit dem Wert "0", sie wird nur auf unterschiedliche Weise beschrieben.

Wenn ein Zeiger mit dem Konstantenliteral "0" verglichen wird, dann wird geprüft, ob der Zeiger ein Nullzeiger ist. Dieses 0 wird dann als Null-Zeiger-Konstante bezeichnet. Der C-Standard definiert, dass 0, das auf den Typ void * gecastet wurde, sowohl ein Null-Zeiger als auch eine Null-Zeiger-Konstante ist.

Um die Lesbarkeit zu verbessern, ist das Makro NULL in der Header-Datei stddef.h enthalten. Abhängig von Ihrem Compiler kann es möglich sein, #undef NULL umzudefinieren und es in etwas Verrücktes umzuwandeln.

Daher sind hier einige gültige Wege, um auf einen Null-Zeiger zu prüfen:

if (pointer == NULL)

NULL ist so definiert, dass es mit einem Null-Zeiger gleichgesetzt wird. Die eigentliche Definition von NULL ist implementierungsabhängig, solange es sich um eine gültige Null-Zeiger-Konstante handelt.

if (pointer == 0)

0" ist eine andere Darstellung der Null-Zeiger-Konstante.

if (!pointer)

Diese if-Anweisung prüft implizit "ist nicht 0", also kehren wir das um und meinen "ist 0".

Die folgenden Methoden sind unzulässig, um auf einen Null-Zeiger zu prüfen:

int mynull = 0;

if (pointer == mynull)

Für den Compiler ist dies keine Prüfung auf einen Null-Zeiger, sondern eine Gleichheitsprüfung für zwei Variablen. Das könnte funktionieren, wenn sich mynull im Code nie ändert und die Compiler-Optimierungen die 0 konstant in die if-Anweisung falten, aber das ist nicht garantiert und der Compiler muss gemäß dem C-Standard mindestens eine Diagnosemeldung (Warnung oder Fehler) ausgeben.

Beachten Sie, was ein Null-Zeiger in der Sprache C ist. Es spielt keine Rolle, welche Architektur zugrunde liegt. Wenn die zugrundeliegende Architektur einen Nullzeigerwert hat, der als Adresse 0xDEADBEEF definiert ist, dann ist es Sache des Compilers, dieses Chaos zu beseitigen.

Selbst auf dieser komischen Architektur sind die folgenden Methoden immer noch gültig, um auf einen Nullzeiger zu prüfen:

if (!pointer)
if (pointer == NULL)
if (pointer == 0)

Die folgenden Methoden sind UNGÜLTIG, um auf einen Null-Zeiger zu prüfen:

#define MYNULL (void *) 0xDEADBEEF
if (pointer == MYNULL)
if (pointer == 0xDEADBEEF)

da diese von einem Compiler als normale Vergleiche angesehen werden.

Null-Zeichen

'\0' ist als Null-Zeichen definiert - das ist ein Zeichen, bei dem alle Bits auf Null gesetzt sind. Dies hat nichts mit Zeigern zu tun. Sie können jedoch etwas ähnliches wie diesen Code sehen:

if (!*string_pointer)

prüft, ob der String-Zeiger auf ein Null-Zeichen zeigt

if (*string_pointer)

prüft, ob der String-Zeiger auf ein Nicht-Null-Zeichen zeigt

Verwechseln Sie diese nicht mit Null-Zeigern. Nur weil die Bit-Darstellung die gleiche ist und dies einige bequeme Crossover-Fälle ermöglicht, sind sie nicht wirklich dasselbe.

Außerdem ist '\0' (wie alle Zeichenliterale) eine Integer-Konstante, in diesem Fall mit dem Wert Null. Somit ist '\0' völlig äquivalent zu einer ungeschmückten 0 Ganzzahlkonstante - der einzige Unterschied liegt in der Intention, die es einem menschlichen Leser vermittelt ("Ich'verwende dies als Nullzeichen.").

Verweise

Siehe Frage 5.3 der comp.lang.c FAQ für mehr. Siehe dieses pdf für den C-Standard. Schauen Sie sich Abschnitt 6.3.2.3 Zeiger, Absatz 3 an.

Kommentare (25)

"NUL" ist nicht 0, sondern bezieht sich auf das ASCII-Zeichen NUL. Zumindest habe ich es so verwendet gesehen. Der Null-Zeiger wird oft als 0 definiert, aber das hängt von der Umgebung ab, in der Sie arbeiten, und von der Spezifikation des Betriebssystems oder der Sprache, die Sie verwenden.

In ANSI C ist der Null-Zeiger als Ganzzahlwert 0 definiert. Jede Welt, in der das nicht der Fall ist, ist also nicht ANSI C-konform.

Kommentare (0)

NULL" ist nicht garantiert gleich 0 - sein genauer Wert ist architekturabhängig. Die meisten wichtigen Architekturen definieren ihn als (void*)0.

'\0' wird immer gleich 0 sein, da dies die Art ist, wie Byte 0 in einem Zeichenliteral kodiert ist.

Ich weiß nicht mehr, ob C-Compiler ASCII verwenden müssen - wenn nicht, ist '0' vielleicht nicht immer gleich 48. Unabhängig davon ist es unwahrscheinlich, dass Sie jemals auf ein System stoßen werden, das einen alternativen Zeichensatz wie EBCDIC verwendet, es sei denn, Sie arbeiten an sehr obskuren Systemen.

Die Größen der verschiedenen Typen unterscheiden sich auf 64-Bit-Systemen, aber die Integer-Werte sind die gleichen.


Einige Kommentatoren haben Zweifel daran geäußert, dass NULL gleich 0 ist, aber nicht null sein soll. Hier ist ein Beispielprogramm, zusammen mit der erwarteten Ausgabe auf einem solchen System:

#include 

int main () {
    size_t ii;
    int *ptr = NULL;
    unsigned long *null_value = (unsigned long *)&ptr;
    if (NULL == 0) {
        printf ("NULL == 0\n"); }
    printf ("NULL = 0x");
    for (ii = 0; ii < sizeof (ptr); ii++) {
        printf ("%02X", null_value[ii]); }
    printf ("\n");
    return 0;
}

Dieses Programm könnte ausgeben:

NULL == 0
NULL = 0x00000001
Kommentare (22)