Was genau passiert in C, wenn Sie einen NULL-Zeiger an strcmp() übergeben?
Lesezeit: 4 Minuten
jfmercer
Ich habe gelesen, dass das Folgende zu undefiniertem Verhalten führt.
strcmp(foo, NULL);
Aber was genau passiert sozusagen „unter der Haube“? Ist foo im Vergleich zu Datenmüll? Ist NULL dereferenziert? Welche Details verursachen “undefiniertes Verhalten”?
Wer sagt, dass die Funktion ausfallen muss?
– Aschepler
18. Februar 2014 um 20:54 Uhr
Nun, Sie können sich immer den Quellcode der Implementierung ansehen …
– Alter Programmierer
18. Februar 2014 um 20:54 Uhr
Der Begriff „undefiniertes Verhalten“ ist absichtlich vage, weil ALLES passieren kann. IRGENDETWAS.
– Annäherung an DarknessFish
18. Februar 2014 um 20:55 Uhr
Undefiniertes Verhalten bedeutet, dass nicht festgelegt ist, was passieren soll. Der Implementierer kann also entscheiden, was er am besten findet. Das Problem, das dadurch entsteht, ist, dass man sich nicht darauf verlassen kann, das Verhalten zu reproduzieren, das man in einem System oder sogar auf demselben System sieht, wenn sich Dinge ändern, z. B. die Laufzeit aktualisiert wird oder das Programm anders kompiliert wird oder das Programm ist unter verschiedenen Bedingungen laufen.
– amit_g
18. Februar 2014 um 21:01 Uhr
@KeithThompson: Sagt “beschränkt auf die Regeln der Physik und Logik”. Schreibt C… 🙂
– Kerrek SB
18. Februar 2014 um 21:21 Uhr
Es hängt von der Implementierung ab, die davon ausgehen kann, dass Ihre Parameter gültig sind (dh in diesem Fall nicht null). Das Verhalten kann von Ausführung zu Ausführung oder von einer Implementierung/Plattform zur anderen reproduzierbar sein oder nicht.
C11 macht dies in 7.1.4, „Verwendung von Bibliotheksfunktionen“ sehr deutlich:
Jede der folgenden Aussagen gilt, sofern in den folgenden detaillierten Beschreibungen nicht ausdrücklich anders angegeben: Wenn ein Argument für eine Funktion einen ungültigen Wert hat (z […] ein Nullzeiger […]) […]ist das Verhalten undefiniert.
Die Beschreibung von strcmp in 7.24.4 steht nichts anderes, also ist das Verhalten tatsächlich undefiniert.
Ja, wie das OP im ersten Satz der Frage bestätigte.
– Keith Thompson
18. Februar 2014 um 21:05 Uhr
Dies ist die aktuelle Implementierung von strcmp in glibc:
/* Compare S1 and S2, returning less than, equal to or
greater than zero if S1 is lexicographically less than,
equal to or greater than S2. */
int
strcmp (p1, p2)
const char *p1;
const char *p2;
{
const unsigned char *s1 = (const unsigned char *) p1;
const unsigned char *s2 = (const unsigned char *) p2;
unsigned char c1, c2;
do
{
c1 = (unsigned char) *s1++;
c2 = (unsigned char) *s2++;
if (c1 == '\0')
return c1 - c2;
}
while (c1 == c2);
return c1 - c2;
}
Nö. Beispielsweise könnten viele Programmierer von Mehrbenutzersystemen mit Speicherschutz erwarten, dass das Dereferenzieren eines Nullzeigers einen Busfehler erzeugt, aber das ist nicht unbedingt auf allen Plattformen der Fall. Sie könnten foo am Ende sehr gut mit der Interrupt-Vektortabelle oder der kapazitiven Ladung nicht angesteuerter Bus-Pins vergleichen.
– Chris Stratton
18. Februar 2014 um 21:04 Uhr
Es beantwortet tatsächlich die Frage. In glibc wird NULL dereferenziert und es wird versucht, die “Strings” zu vergleichen. Je nachdem, wie das System auf Versuche reagiert, die Speicheradressen 0,1,2… zu lesen, wird entweder der entsprechende Fehler erzeugt oder der Zeichenfolge wird mit Datenmüll verglichen.
– Wahrhaftigkeit
18. Februar 2014 um 21:06 Uhr
Es beantwortet die Frage nicht, weil Sie nicht wissen, dass glibc verwendet wird, und weil Sie zugeben, dass selbst dort, wo glibc verwendet wird, was passiert, davon abhängt, wie das Hostsystem auf einen Versuch reagiert, einen Nullzeiger zu dereferenzieren.
– Chris Stratton
19. Februar 2014 um 16:11 Uhr
Interessantes Detail im Code hier, der die Tatsache ausnutzt, dass die normalerweise für vorzeichenlose Typen verwendete modulare Arithmetik nicht für c1-c2 verwendet wird, da der Ergebnistyp vorzeichenbehaftet ist. Um dieses Verhalten zu bekommen, müsste man schreiben return (unsigned char)(c1 - c2);.
– Joachim Wagner
23. Oktober 2017 um 10:42 Uhr
Sie übergeben zwei Zeiger und strcmp dereferenziert ihren Inhalt und vergleicht, bis er auf den Unterschied oder das Nullzeichen trifft. Fehler treten auf verschiedenen Abstraktionsebenen auf, strcmp ist für sich genommen fehlerfrei. Viele Systeme generieren SIGSEGV-Zeichen beim Dereferenzieren von NULL-Zeigern, aber dies ist nicht die Voraussetzung.
Bitte beachten Sie, dass ISO-Standards nicht viele Dinge definieren und Implementierungsdetails den Implementierungen überlassen. Auf ISO C-Niveau ist an Ihrem Beispiel nichts auszusetzen, aber die Ergebnisse sind nicht garantiert vorhersehbar. (Und kein praktischer Test ist garantiert präzise und reproduzierbar, es sei denn, Sie konsultieren die Regeln des zugrunde liegenden Systems und sie sagen etwas anderes).
Wenn wir von Abstraktionsebenen sprechen, können wir nicht fragen „was wäre wenn“, weil die Regeln klar sind und sagen „tu das nicht, Verhalten ist hier nicht definiert“.
13716400cookie-checkWas genau passiert in C, wenn Sie einen NULL-Zeiger an strcmp() übergeben?yes
Wer sagt, dass die Funktion ausfallen muss?
– Aschepler
18. Februar 2014 um 20:54 Uhr
Nun, Sie können sich immer den Quellcode der Implementierung ansehen …
– Alter Programmierer
18. Februar 2014 um 20:54 Uhr
Der Begriff „undefiniertes Verhalten“ ist absichtlich vage, weil ALLES passieren kann. IRGENDETWAS.
– Annäherung an DarknessFish
18. Februar 2014 um 20:55 Uhr
Undefiniertes Verhalten bedeutet, dass nicht festgelegt ist, was passieren soll. Der Implementierer kann also entscheiden, was er am besten findet. Das Problem, das dadurch entsteht, ist, dass man sich nicht darauf verlassen kann, das Verhalten zu reproduzieren, das man in einem System oder sogar auf demselben System sieht, wenn sich Dinge ändern, z. B. die Laufzeit aktualisiert wird oder das Programm anders kompiliert wird oder das Programm ist unter verschiedenen Bedingungen laufen.
– amit_g
18. Februar 2014 um 21:01 Uhr
@KeithThompson: Sagt “beschränkt auf die Regeln der Physik und Logik”. Schreibt C… 🙂
– Kerrek SB
18. Februar 2014 um 21:21 Uhr