Ist NULL in C immer Null?

Lesezeit: 6 Minuten

Ich habe gestern einen Mann für eine Position im mittleren Software-Engineering interviewt, und er erwähnte, dass NULL in C nicht immer Null ist und dass er Implementierungen von C gesehen hat, bei denen NULL nicht Null ist. Ich finde das sehr verdächtig, aber ich möchte sicher sein. Weiß jemand, ob er recht hat?

(Die Antworten haben keinen Einfluss auf mein Urteil über diesen Kandidaten, ich habe meine Entscheidung bereits meinem Vorgesetzten übermittelt.)

  • bytes.com/topic/c/answers/213647-null-c

    – Soandos

    27. März 2012 um 16:50 Uhr

  • verwandter stackoverflow.com/questions/459743/is-null-always-false

    – Makabral

    27. März 2012 um 16:52 Uhr

  • c-faq.com/null/index.html

    – Jouni K. Seppänen

    27. März 2012 um 16:53 Uhr

  • Nein, aber Null ist immer NULL.

    – Philipp

    27. März 2012 um 17:08 Uhr

  • @ Philipp: int x = 0; void *p = (void *) x; Hier, x hat den Wert Null, aber x ist nicht die wörtliche Null, also p ist nicht garantiert NULLund auf einigen bizarren Plattformen wird es das tatsächlich nicht sein NULL. Auf der anderen Seite, void *q = 0; immer zuweist NULL zu q, egal auf welcher Plattform. „Wörtlich“ hat in diesem Zusammenhang eine technische Bedeutung. Suchen Sie nach “ganzzahliges Literal”.

    – Dietrich Ep

    6. November 2012 um 23:08 Uhr


Benutzeravatar von Oliver Charlesworth
Oliver Charlesworth

Ich nehme an, Sie meinen den Nullzeiger. Es ist garantiert gleich zu vergleichen 0.1 Aber es muss nicht mit All-Null-Bits dargestellt werden.2

Siehe auch die comp.lang.c FAQ auf Nullzeigern.


  1. Siehe C99, 6.3.2.3.
  2. Es gibt keinen expliziten Anspruch; aber siehe die Fußnote für C99, 7.20.3 (Dank an @birryree in den Kommentaren).

  • Als Nachtrag zu Ihrer C99-Referenz, as NULL ist immer gleich 0 (Null-Zeiger-Konstante), Abschnitt 7.20.3.2 weist auch darauf hin, dass alle Bits auf Null gesetzt sind (wie der Fall für calloc) ist nicht unbedingt dasselbe wie die Darstellung von 0.0f oder Ganzzahl 0.

    – Wo

    27. März 2012 um 16:57 Uhr


  • Genial. Heutzutage ist es also ziemlich üblich, aber keine Voraussetzung. Vielen Dank.

    – chi42

    27. März 2012 um 16:59 Uhr

  • Wenn ich also einen NULL-Zeiger auf ein int umwandeln und dann drucken würde, würde ich nicht ‘0’ drucken? Bedeutet das, dass der Compiler sich merken muss, wann er einen Zeigervergleich durchführt, damit er einen NULL-Zeiger gleich Null vergleichen kann?

    – chi42

    27. März 2012 um 17:02 Uhr

  • @chi42: Der Standard sagt nichts darüber aus, was passiert, wenn Sie einen Zeiger (einen beliebigen Zeiger) in ein int konvertieren, außer dass es implementierungsdefiniert ist. Siehe erneut 6.3.2.3.

    – Oliver Charlesworth

    27. März 2012 um 17:04 Uhr

  • Wie kann NULL gleich 0 sein, dessen Bit-Darstellung alle Nullen sind (richtig?), aber immer noch gleich 0 sein?

    – einpoklum

    30. Juni 2021 um 20:24 Uhr

§ 6.3.2.3 des C99-Standards sagt

Ein ganzzahliger konstanter Ausdruck mit dem Wert 0 oder ein solcher in den Typ void * umgewandelter Ausdruck wird als Nullzeigerkonstante bezeichnet Vergleichen Sie ungleich mit einem Zeiger auf ein Objekt oder eine Funktion.

§ 7.17 sagt auch

[…] NULL, das zu einer implementierungsdefinierten Nullzeigerkonstante erweitert wird […]

Die Adresse des NULL-Zeigers kann von 0 abweichen, verhält sich aber in den meisten Fällen so.

(Dies sollte das gleiche sein wie in älteren C-Standards, die ich gerade nicht zur Hand habe)

Der Nullzeiger Konstante ist immer 0. Die NULL Makro kann von der Implementierung als nackt definiert werden 0oder ein Cast-Ausdruck wie (void *) 0oder ein anderer nullwertiger ganzzahliger Ausdruck (daher die “implementierungsdefinierte” Sprache im Standard).

Der Nullzeiger Wert kann etwas anderes als 0 sein. Wenn eine Nullzeigerkonstante angetroffen wird, wird sie in den richtigen Nullzeigerwert konvertiert.

  • Färben Sie mich dumm, aber ich fürchte, ich brauche jetzt mehr Bildung. Wenn Sie einen Zeiger haben ptrist es nicht ptr==NULL exakt das Gleiche wie ptr==0 oder !ptr? Ist diese Implementierung abhängig?

    – Herr Lister

    27. März 2012 um 19:21 Uhr

  • @MrLister: Im Kontext deiner Quellcodeda hast du vollkommen recht – ptr == 0 und ptr == NULL und !ptr sind alle gleichwertig. Sobald der Quellcode jedoch in Maschinencode übersetzt wurde, kann der tatsächliche Nullzeigerwert etwas anderes als 0 sein (und alle diese Vergleiche werden gegen diesen tatsächlichen Nullzeigerwert durchgeführt).

    – Johannes Bode

    27. März 2012 um 23:48 Uhr

  • The null pointer value may be something other than 0 – meinst du *ptr == something selbst wenn void *ptr = 0?

    – Incerteza

    7. September 2014 um 9:58 Uhr

  • @AlexanderSupertramp: Ich meine, dass die Laufzeitumgebung in dem ein Programm ausgeführt wird, kann einen anderen Wert als 0 verwenden, um einen “Null”-Zeiger darzustellen (d. h. eine wohldefinierte ungültig Adresswert). Auf manchen Systemen 0 kann eine vollkommen gültige Speicheradresse sein, auf die Ihr Programm zugreifen kann, und ein anderer Wert (wie beispielsweise 0xFFFFFFFF) kann für “null” verwendet werden. Allerdings innerhalb Ihrer Quellcodewird immer ein 0-wertiger Ausdruck verwendet, um die darzustellen NULL Zeiger konstant.

    – Johannes Bode

    27. Februar 2015 um 17:58 Uhr

  • Nur eine Noob-Frage: Wollte nur wissen, ob ich richtig liege, wenn ich sage “der Wert von a null Zeiger ist gleich dem Wert, der in einer Speicherstelle enthalten ist, wobei diese Speicherstelle willkürlich ausgewählt (nur erraten) oder vom Compiler zur Laufzeit und beim Schreiben ausgewählt wird char *p = NULL; dann zeigt p auf diesen Speicherort.”. Bitte korrigieren Sie mich.

    – ajaysinghnegi

    2. August 2019 um 8:46 Uhr


Benutzeravatar von twol
zwöl

In C gibt es einen und nur einen Kontext, in dem es notwendig ist, eine Nullzeigerkonstante explizit in einen bestimmten Zeigertyp umzuwandeln, damit das Programm korrekt funktioniert. Dieser Kontext leitet einen Nullzeiger durch eine nicht typisierte Funktionsargumentliste. Im modern C passiert dies nur, wenn Sie einen Nullzeiger an eine Funktion übergeben müssen, die eine variable Anzahl von Argumenten akzeptiert. (In Legacy C passiert es mit jeder Funktion, die nicht mit einem Prototyp deklariert ist.) Das paradigmatische Beispiel ist execlwobei das allerletzte Argument ein NULL-Zeiger sein muss, in den explizit umgewandelt wird (char *):

execl("/bin/ls", "ls", "-l", (char *)0);    // correct
execl("/bin/ls", "ls", "-l", (char *)NULL); // correct, but unnecessarily verbose

execl("/bin/ls", "ls", "-l", 0);            // undefined behavior
execl("/bin/ls", "ls", "-l", NULL);         // ALSO undefined behavior

Ja, das letzte Beispiel hat undefiniertes Verhalten selbst wenn NULL ist definiert als ((void *)0)Weil void * und char * sind nicht implizit ineinander umwandelbar, wenn sie durch eine nicht typisierte Argumentliste geleitet werden, obwohl sie sich sonst überall befinden. (Es gibt eine Sprache in C2011, die sie implizit interkonvertierbar macht, wenn sie durchlaufen werden va_argaber sie haben vergessen anzugeben, dass von der Implementierung bereitgestellte Bibliotheksfunktionen auf verschiedene Argumente zugreifen, als ob sie aufgerufen würden va_arg, daher können Sie sich nur für verschiedene Funktionen, die Teil Ihres Programms sind, darauf verlassen. Jemand sollte wahrscheinlich eine DR einreichen.)

„Unter der Haube“ ist hier das Problem nicht nur mit dem Bitmuster, das für einen Nullzeiger verwendet wird, aber dass der Compiler möglicherweise den genauen konkreten Typ jedes Arguments kennen muss, um einen Aufrufrahmen korrekt einzurichten. (Betrachten Sie den MC68000 mit seinen separaten Adress- und Datenregistern; einige ABIs spezifizierten Zeigerargumente, die in Adressregistern übergeben werden sollen, aber ganzzahlige Argumente in Datenregistern. Betrachten Sie auch alle ABI wo int und void * sind nicht gleich groß. Und es ist heutzutage verschwindend selten, aber C sieht immer noch explizit vor void * und char * nicht die gleiche Größe haben. [EDIT: I’m not sure, but this may no longer be permitted.]) Wenn ein Funktionsprototyp vorhanden ist, kann der Compiler diesen verwenden, aber Funktionen ohne Prototypen und variadische Argumente bieten keine solche Unterstützung.

C++ ist komplizierter und ich fühle mich nicht qualifiziert zu erklären, wie.

Benutzeravatar von pizza
Pizza

Bei einigen Implementierungen ist die Größe des Zeigers nicht die gleiche wie die Größe der Ganzzahl. NULL im Integer-Kontext ist 0, aber das tatsächliche binäre Layout muss nicht nur 0 sein.

1416000cookie-checkIst NULL in C immer Null?

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

Privacy policy