Speichern des EOF-Zeichens (End of File) in einem Zeichentyp
On Februar 18, 2021 by admin Ich habe in Dennis Ritchies The C Programming Language gelesen Buch, dass int
verwendet werden muss, damit eine Variable EOF enthält –, damit sie ausreichend groß ist, damit sie den EOF-Wert – nicht char
. Der folgende Code funktioniert jedoch einwandfrei:
#include<stdio.h> main() { char c; c=getchar(); while(c!=EOF) { putchar(c); c=getchar(); } }
Wenn dort ist keine Eingabe mehr, getchar
gibt EOF zurück. Und im obigen Programm kann die Variable c
mit char-Typ diese halten erfolgreich.
Warum funktioniert das? Gemäß der Erklärung im oben genannten Buch sollte der Code nicht funktionieren.
Kommentare
- Es gibt kein EOF-Zeichen.
- Dieser Code schlägt wahrscheinlich fehl, wenn Sie ein Zeichen mit dem Wert
0xff
. Speichern des Ergebnisses vongetchar()
in einemint
löst dieses Problem. Ihre Frage entspricht im Wesentlichen der Frage 12.1 in der FAQ comp.lang.c , die eine hervorragende Ressource darstellt. (Außerdem solltemain()
int main(void)
sein, und es würde ' nicht schaden, a hinzuzufügenreturn 0;
vor dem Schließen}
.) - @delnan: Der verknüpfte Artikel ist nicht ' Es ist nicht ganz richtig, wie Unix Control-D behandelt. ' schließt den Eingabestream nicht. Es bewirkt lediglich, dass fread (), das auf der Konsole blockiert ist, sofort mit noch nicht gelesenen Daten zurückkehrt. Viele Programme interpretieren eine Null-Byte-Rückgabe von fread () als Hinweis auf EOF, aber die Datei bleibt tatsächlich geöffnet und kann mehr Eingaben liefern.
Antwort
Ihr Code scheint zu funktionieren, da die impliziten Typkonvertierungen versehentlich das Richtige bewirken.
getchar()
Gibt ein int
mit einem Wert zurück, der entweder in den Bereich von unsigned char
passt oder EOF
( was negativ sein muss, normalerweise ist es -1). Beachten Sie, dass EOF
selbst kein Zeichen ist, sondern ein Signal dafür, dass keine weiteren Zeichen verfügbar sind.
Beim Speichern des Ergebnisses von getchar()
In c
gibt es zwei Möglichkeiten. Entweder kann der Typ char
den Wert darstellen. In diesem Fall ist dies der Wert von c
. Oder der Typ char
kann den Wert nicht darstellen. In diesem Fall ist nicht definiert, was passieren wird. Intel-Prozessoren hacken nur die hohen Bits ab, die nicht in den neuen Typ passen (wodurch der Wert modulo 256 für char
effektiv reduziert wird), aber darauf sollten Sie sich nicht verlassen. P. >
Der nächste Schritt besteht darin, c
mit EOF
zu vergleichen. Wie EOF
ist Ein int
, c
wird ebenfalls in ein int
konvertiert, wobei der gespeicherte Wert erhalten bleibt in c
. Wenn c
den Wert von EOF
speichern könnte, ist der Vergleich erfolgreich Wenn jedoch c
den Wert nicht speichern konnte, schlägt der Vergleich fehl, da beim Konvertieren von , um char
einzugeben.
Ihr Compiler hat anscheinend den Typ char
gewählt signiert und der Wert von EOF
klein genug, um in char
zu passen. Wenn char
ohne Vorzeichen wäre (oder wenn Sie unsigned char
verwendet hätten), wäre Ihr Test fehlgeschlagen, weil unsigned char
kann den Wert von EOF
nicht enthalten.
Beachten Sie auch, dass es ein zweites Problem mit Ihrem Code gibt. Als EOF
ist kein Zeichen selbst, aber Sie erzwingen es in einen char
-Typ. Es gibt sehr wahrscheinlich ein Zeichen, das als EOF
und für die Hälfte der möglichen Zeichen ist nicht definiert, ob sie korrekt verarbeitet werden.
Kommentare
- Erzwingen Um
char
Werte außerhalb des BereichsCHAR_MIN
einzugeben, istCHAR_MAX
erforderlich, um eine der beiden Ausbeuten zu erzielen Ein implementierungsdefinierter Wert ergibt ein Bitmuster, das die Implementierung als Trap-Darstellung definiert, oder löst ein implementierungsdefiniertes Signal aus. In den meisten Fällen müssten Implementierungen Gehen Sie viel zusätzliche Arbeit durch, um etwas anderes als zwei ' s-Komplement-Reduktion zu tun.Wenn die Mitglieder des Normungsausschusses der Idee zustimmen würden, dass Compiler dazu ermutigt werden sollten, Verhaltensweisen zu implementieren, die mit denen der meisten anderen Compiler übereinstimmen, ohne dass Gründe dafür vorliegen … - … würde ich dies in Betracht ziehen Zwang als zuverlässig (nicht zu sagen, dass Code ' seine Absichten nicht dokumentieren sollte, aber dass
(signed char)x
klarer und genauso betrachtet werden sollte sicher wie((unsigned char)x ^ CHAR_MAX+1))-(CHAR_MAX+1)
.) Wie es ist, sehe ich ' keine Wahrscheinlichkeit, dass Compiler ein anderes Verhalten implementieren, das der heutigen ' s Standard; Die einzige Gefahr besteht darin, dass der Standard geändert wird, um das Verhalten im angeblichen Interesse der " -Optimierung " zu brechen. - @supercat: Der Standard ist so geschrieben, dass kein Compiler Code erzeugen muss, dessen Verhalten von dem Prozessor, auf den er abzielt, natürlich nicht unterstützt wird. Der größte Teil des undefinierten Verhaltens ist vorhanden, da sich (zum Zeitpunkt des Schreibens des Standards) nicht alle Prozessoren konsistent verhalten haben. Mit zunehmender Reife der Compiler haben Compiler-Autoren begonnen, das undefinierte Verhalten zu nutzen, um aggressivere Optimierungen vorzunehmen.
- Historisch gesehen war die Absicht des Standards größtenteils so, wie Sie es beschreiben, obwohl der Standard einige Verhaltensweisen in beschreibt Ausreichend detailliert, um Compiler für einige gängige Plattformen zu benötigen, um mehr Code zu generieren, als nach einer lockeren Spezifikation erforderlich wäre. Der Typ Zwang in
int i=129; signed char c=i;
ist ein solches Verhalten. Relativ wenige Prozessoren haben eine Anweisung, mit derc
gleichi
wird, wenn ' aktiviert ist den Bereich von -127 bis +127 und würde eine konsistente Zuordnung anderer Werte voni
zu Werten im Bereich von -128 bis +127 ergeben, die sich von zwei s-Komplement-Reduktion oder … - … würde in solchen Fällen konsequent ein Signal auslösen. Da der Standard verlangt, dass Implementierungen entweder eine konsistente Zuordnung liefern oder ein Signal konsistent auslösen, wären die einzigen Plattformen, auf denen der Standard Platz für etwas anderes als zwei ' s-Komplementreduzierung lässt, Dinge wie DSPs mit sättigender arithmetischer Hardware. In Bezug auf die historische Grundlage für undefiniertes Verhalten würde ich sagen, dass das Problem nicht nur bei Hardwareplattformen ' liegt. Selbst auf einer Plattform, auf der sich der Überlauf sehr konsistent verhält, kann es nützlich sein, dass ein Compiler ihn abfängt …
Schreibe einen Kommentar