it-swarm.com.de

Ist NULL in C immer Null?

Ich habe gestern einen Typen für eine mittlere Position im Bereich 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 werden mein Urteil über diesen Kandidaten nicht beeinträchtigen. Ich habe meine Entscheidung bereits meinem Manager vorgelegt.)

54
chi42

Ich gehe davon aus, dass Sie den Nullzeiger meinen. Es ist garantiert, 0 zu vergleichen.1 Es muss jedoch nicht mit Null-Bits dargestellt werden.2

Siehe auch comp.lang.c FAQ über Nullzeiger.


  1. Siehe C99, 6.3.2.3.
  2. Es gibt keinen expliziten Anspruch. Siehe aber die Fußnote zu C99, 7.20.3 (Dank an @birryree in den Kommentaren) . </ sub>
50

Der Nullzeiger constant ist immer 0. Das Makro NULL kann durch die Implementierung als nackter 0 oder einen Umwandlungsausdruck wie (void *) 0 oder einen anderen ganzzahligen Ausdruck mit dem Wert Null definiert werden (daher die "implementierungsdefinierte" Sprache in Der Standard). 

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

12
John Bode

§ 6.3.2.3 der C99-Norm sagt

Ein ganzzahliger konstanter Ausdruck mit dem Wert 0 oder ein solcher Ausdruck, der in den Typ .__ umgewandelt wird. void *, wird als Nullzeigerkonstante bezeichnet) Wenn eine Nullzeigerkonstante in eine .__-Datei konvertiert wird. Der Zeigertyp, der resultierende Zeiger, der als Nullzeiger bezeichnet wird, vergleicht garantiert ungleich zu einem Zeiger auf ein beliebiges Objekt oder eine Funktion.

§ 7.17 sagt auch

[...] NULL, das sich auf eine implementierungsdefinierte Nullzeiger-Konstante erweitert [...]

Die Adresse des NULL-Zeigers unterscheidet sich möglicherweise von 0, während er sich in den meisten Fällen so verhält, wie er war.

(Dies sollte derselbe sein wie bei älteren C-Standards, die ich momentan nicht zur Hand habe.)

12
johannes

In C gibt es einen und nur einen Kontext, in dem eine Nullzeiger-Konstante explizit in einen bestimmten Zeigertyp umgewandelt werden muss, damit das Programm korrekt arbeitet. Dieser Kontext übergibt einen Nullzeiger durch eine nicht typisierte Funktionsargumentliste. In modern C geschieht dies nur, wenn Sie einen Nullzeiger an eine Funktion übergeben müssen, die eine variable Anzahl von Argumenten verwendet. (In Legacy C geschieht dies mit jeder Funktion, die nicht mit einem Prototyp deklariert wurde.) Das Paradigmatierbeispiel ist execl , wobei das letzte Argument ein Nullzeiger sein muss, der explizit in (char *) umgewandelt wird:

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 ein undefiniertes Verhalten , auch wennNULL als ((void *)0) definiert ist, da void * und char *nicht implizit interkonvertierbar sind, wenn sie durch eine untypisierte Argumentliste geleitet werden, auch wenn sie überall vorhanden sind.

"Unter der Haube" ist das Problem hier nicht, nur mit dem Bitmuster, das für einen Nullzeiger verwendet wird, aber der Compiler muss möglicherweise den genauen Typ jedes Arguments kennen, um einen Aufrufrahmen richtig einzurichten . (Betrachten Sie den MC68000 mit seinen separaten Adress- und Datenregistern; einige von ABIs angegebene Zeigerargumente, die in Adressregistern, aber ganzzahlige Argumente in Datenregistern übergeben werden.) Beachten Sie auch alle ABI, bei denen int und void * nicht dieselbe Größe haben , aber C gibt weiterhin explizit an, dass void * und char * nicht die gleiche Größe haben.) Wenn es einen Funktionsprototyp gibt, kann der Compiler dies verwenden, aber nicht prototypisierte Funktionen und variadische Argumente bieten keine solche Unterstützung.

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

7
zwol

Er hat recht, bei einigen Implementierungen stimmt die Größe des Zeigers nicht mit der Größe der Ganzzahl überein. NULL im Ganzzahl-Kontext ist 0, aber das tatsächliche binäre Layout muss nicht alle 0 sein.

0
pizza