C
Der Buchstabe "x" ist in einer Datei verloren gegangen. Ein Programm wurde geschrieben, um es zu finden:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
FILE* fp = fopen("desert_file", "r");
char letter;
char missing_letter = argv[1][0];
int found = 0;
printf("Searching file for missing letter %c...\n", missing_letter);
while( (letter = fgetc(fp)) != EOF ) {
if (letter == missing_letter) found = 1;
}
printf("Whole file searched.\n");
fclose(fp);
if (found) {
printf("Hurray, letter lost in the file is finally found!\n");
} else {
printf("Haven't found missing letter...\n");
}
}
Es wurde kompiliert und lief und es schrie schließlich:
Hurray, letter lost in the file is finally found!
Seit vielen Jahren werden Briefe auf diese Weise gerettet, bis der neue Typ kam und den Code optimierte. Er war mit Datentypen vertraut und wusste, dass es besser ist, vorzeichenlose statt vorzeichenbehaftete Werte zu verwenden, da diese einen größeren Bereich haben und einen gewissen Schutz vor Überläufen bieten. Also hat er int in unsigned int geändert . Er kannte Ascii auch gut genug, um zu wissen, dass sie immer einen nicht negativen Wert haben. Also hat er auch char in unsigned char geändert . Er kompilierte den Code und ging stolz auf seine gute Arbeit nach Hause. Das Programm sah so aus:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
FILE* fp = fopen("desert_file", "r");
unsigned char letter;
unsigned char missing_letter = argv[1][0];
unsigned int found = 0;
printf("Searching file for missing letter %c...\n", missing_letter);
while( (letter = fgetc(fp)) != EOF ) {
if (letter == missing_letter) found = 1;
}
printf("Whole file searched.\n");
fclose(fp);
if (found) {
printf("Hurray, letter lost in the file is finally found!\n");
} else {
printf("Haven't found missing letter...\n");
}
}
Er kam am nächsten Tag zu einem Chaos zurück. Der Buchstabe "a" fehlte und obwohl er in der "desert_file" mit "abc" enthalten sein sollte, suchte das Programm danach und gab nur Folgendes aus:
Searching file for missing letter a...
Sie entließen den Kerl und kehrten zur vorherigen Version zurück, wobei sie sich daran erinnerten, dass man Datentypen im Arbeitscode niemals optimieren sollte.
Aber welche Lektion hätten sie hier lernen sollen?
Wenn Sie sich zunächst die ASCII-Tabelle ansehen, werden Sie feststellen, dass es keine EOF gibt. Dies liegt daran, dass EOF kein Zeichen ist, sondern ein spezieller Wert, der von fgetc () zurückgegeben wird. Dabei kann entweder ein Zeichen zurückgegeben werden, das auf int erweitert ist, oder -1, das das Dateiende angibt.
Solange wir signiertes Zeichen verwenden, funktioniert alles einwandfrei - Zeichen gleich 50 wird durch fgetc () ebenfalls in int gleich 50 erweitert. Dann wandeln wir es wieder in char um und haben immer noch 50. Gleiches gilt für -1 oder eine andere Ausgabe von fgetc ().
Aber schauen Sie, was passiert, wenn wir unsignierte Zeichen verwenden. Wir beginnen mit einem Zeichen in fgetc (), erweitern es auf int und möchten dann ein vorzeichenloses Zeichen haben. Das einzige Problem ist, dass wir -1 in nicht signiertem Zeichen nicht beibehalten können. Das Programm speichert es als 255, was nicht mehr EOF entspricht.
Vorbehalt
Wenn Sie sich Abschnitt 3.1.2.5 Typen in Kopie der ANSI C-Dokumentation ansehen, werden Sie feststellen, dass die Signatur von char ausschließlich von der Implementierung abhängt. Also sollte der Typ wahrscheinlich nicht entlassen werden, da er einen sehr kniffligen Fehler im Code gefunden hat. Es könnte herauskommen, wenn der Compiler geändert oder auf eine andere Architektur umgestellt wird. Ich frage mich, wer gefeuert werden würde, wenn der Bug in einem solchen Fall herauskommen würde;)
PS. Das Programm wurde um den in der PC-Assemblersprache von Paul A. Carter erwähnten Fehler herum erstellt