Ich versuche, diesen Code aus dem Buch "The C Programming Language" (K & R) zu kompilieren. Es ist eine reine Version des UNIX-Programms wc
:
#include <stdio.h>
#define IN 1; /* inside a word */
#define OUT 0; /* outside a word */
/* count lines, words and characters in input */
main()
{
int c, nl, nw, nc, state;
state = OUT;
nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == '\n')
++nl;
if (c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
Und ich bekomme folgenden Fehler:
$ gcc wc.c
wc.c: In function ‘main’:
wc.c:18: error: ‘else’ without a previous ‘if’
wc.c:18: error: expected ‘)’ before ‘;’ token
Die 2. Ausgabe dieses Buches stammt aus dem Jahr 1988 und ich bin ziemlich neu in C. Vielleicht hat es mit der Compiler-Version zu tun, oder vielleicht spreche ich nur Unsinn.
Ich habe im modernen C-Code eine andere Verwendung der main
Funktion gesehen:
int main()
{
/* code */
return 0;
}
Ist dies ein neuer Standard oder kann ich trotzdem eine typlose Hauptleitung verwenden?
|| c = '\t')
. Scheint das der gleiche zu sein wie der andere Code in dieser Zeile?Antworten:
Ihr Problem liegt in Ihren Präprozessordefinitionen von
IN
undOUT
:Beachten Sie, wie Sie in jedem von ihnen ein abschließendes Semikolon haben. Wenn der Präprozessor sie erweitert, sieht Ihr Code ungefähr so aus:
Dieses zweite Semikolon bewirkt
else
, dass das nichtif
als Übereinstimmung vorhanden ist, da Sie keine geschweiften Klammern verwenden. Entfernen Sie also die Semikolons aus den Präprozessordefinitionen vonIN
undOUT
.Die hier gewonnene Erkenntnis ist, dass Präprozessoranweisungen nicht mit einem Semikolon enden müssen.
Außerdem sollten Sie immer Zahnspangen verwenden!
else
Der obige Code enthält keine hängenden Mehrdeutigkeiten.quelle
Das Hauptproblem bei diesem Code ist, dass es sich nicht um den Code von K & R handelt. Es enthält Semikolons nach den Makrodefinitionen, die im Buch nicht vorhanden waren und die, wie andere hervorgehoben haben, die Bedeutung ändern.
Außer wenn Sie Änderungen vornehmen, um den Code zu verstehen, sollten Sie ihn in Ruhe lassen, bis Sie ihn verstanden haben. Sie können Code, den Sie verstehen, nur sicher ändern.
Dies war wahrscheinlich nur ein Tippfehler von Ihrer Seite, aber es zeigt die Notwendigkeit des Verstehens und der Aufmerksamkeit für Details beim Programmieren.
quelle
Nach den Makros sollten keine Semikolons stehen.
und es sollte wahrscheinlich sein
quelle
;
sei ein Tippfehler, der das Problem nicht beeinträchtige. Dies bedeutet einen Tippfehler in Ihrer Frage und nicht in dem Code, den Sie tatsächlich verwendet haben.Die Definitionen von IN und OUT sollten folgendermaßen aussehen:
Die Semikolons verursachten das Problem! Die Erklärung ist einfach: Sowohl IN als auch OUT sind Präprozessoranweisungen. Im Wesentlichen ersetzt der Compiler alle Vorkommen von IN durch eine 1 und alle Vorkommen von OUT durch eine 0 im Quellcode.
Da der ursprüngliche Code nach der 1 und der 0 ein Semikolon hatte, erzeugte das zusätzliche Semikolon nach der Nummer beim Ersetzen von IN und OUT im Code einen ungültigen Code, zum Beispiel diese Zeile:
Am Ende sah es so aus:
Aber was Sie wollten, war Folgendes:
Lösung: Entfernen Sie das Semikolon nach den Zahlen in der ursprünglichen Definition.
quelle
Wie Sie sehen, gab es ein Problem mit Makros.
GCC hat die Option , nach der Vorverarbeitung anzuhalten. (-E) Diese Option ist nützlich, um das Ergebnis der Vorverarbeitung anzuzeigen. Tatsächlich ist die Technik wichtig, wenn Sie mit einer großen Codebasis in c / c ++ arbeiten. In der Regel haben Makefiles ein Ziel, das nach der Vorverarbeitung gestoppt werden soll.
Zum schnellen Nachschlagen: Die SO-Frage behandelt die Optionen: Wie wird eine C / C ++ - Quelldatei nach der Vorverarbeitung in Visual Studio angezeigt? . Es beginnt mit vc ++, hat aber auch die unten genannten gcc-Optionen .
quelle
Nicht gerade ein Problem, aber die Erklärung von
main()
ist auch datiert, es sollte so etwas sein.Der Compiler wird einen int-Rückgabewert für eine Funktion ohne einen annehmen, und ich bin sicher, dass der Compiler / Linker das Fehlen einer Deklaration für argc / argv und das Fehlen eines Rückgabewerts umgehen wird, aber sie sollten vorhanden sein.
quelle
Fügen Sie explizite Klammern um Codeblöcke ein. Der K & R-Stil kann mehrdeutig sein.
Schauen Sie sich Zeile 18 an. Der Compiler teilt Ihnen mit, wo das Problem liegt.
quelle
if
Block hinzufügen und vergessen, die geschweiften Klammern hinzuzufügen, da Ihr Block jetzt mehr als eine Zeile enthält, kann es eine Weile dauern, bis dieser Fehlerif
Klausel Anweisungen hinzuzufügen und die Klammern zu "vergessen", dann sind Sie es nicht ein sehr guter Programmierer.Eine einfache Möglichkeit besteht darin, Klammern wie {} für jedes zu verwenden
if
undelse
:quelle
Wie andere Antworten betonten, liegt das Problem in
#define
und Semikolons. Um diese Probleme zu minimieren, definiere ich Zahlenkonstanten immer wie folgtconst int
:Auf diese Weise werden Sie viele Probleme und mögliche Probleme los. Es ist nur durch zwei Dinge begrenzt:
Ihr Compiler muss unterstützen
const
- was 1988 im Allgemeinen nicht der Fall war, aber jetzt wird es von allen häufig verwendeten Compilern unterstützt. (AFAIK dasconst
ist von C ++ "entlehnt".)Sie können diese Konstanten nicht an bestimmten Stellen verwenden, an denen Sie eine stringähnliche Konstante benötigen würden. Aber ich denke, Ihr Programm ist nicht so.
quelle
const int
die in C nicht möglich sind.