J'essaye de compiler ce morceau de code du livre "The C Programming Language" (K & R). Il s'agit d'une version simple du programme UNIX 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);
}
Et j'obtiens l'erreur suivante:
$ gcc wc.c
wc.c: In function ‘main’:
wc.c:18: error: ‘else’ without a previous ‘if’
wc.c:18: error: expected ‘)’ before ‘;’ token
La 2ème édition de ce livre date de 1988 et je suis assez nouveau en C. Peut-être que cela a à voir avec la version du compilateur ou peut-être que je dis juste des bêtises.
J'ai vu dans le code C moderne une utilisation différente de la main
fonction:
int main()
{
/* code */
return 0;
}
Est-ce une nouvelle norme ou puis-je toujours utiliser un main sans type?
|| c = '\t')
. Cela ressemble-t-il à l'autre code sur cette ligne?Réponses:
Votre problème concerne vos définitions de préprocesseur de
IN
etOUT
:Remarquez comment vous avez un point-virgule de fin dans chacun de ces éléments. Lorsque le préprocesseur les développe, votre code ressemblera à peu près à:
Ce deuxième point-virgule fait que le
else
n'a aucun précédentif
comme correspondance, car vous n'utilisez pas d'accolades. Supprimez donc les points-virgules des définitions de préprocesseur deIN
etOUT
.La leçon apprise ici est que les instructions du préprocesseur ne doivent pas nécessairement se terminer par un point-virgule.
De plus, vous devriez toujours utiliser des accolades!
Il n'y a pas d'
else
ambiguïté suspendue dans le code ci-dessus.la source
Le principal problème avec ce code est qu'il ne s'agit pas du code de K&R. Il comprend des points-virgules après les définitions de macros, qui n'étaient pas présentes dans le livre, qui, comme d'autres l'ont souligné, modifie la signification.
Sauf lorsque vous effectuez un changement pour tenter de comprendre le code, vous devez le laisser seul jusqu'à ce que vous le compreniez. Vous ne pouvez modifier en toute sécurité que le code que vous comprenez.
Ce n'était probablement qu'une faute de frappe de votre part, mais cela illustre le besoin de compréhension et d'attention aux détails lors de la programmation.
la source
Il ne devrait y avoir aucun point-virgule après les macros,
et ça devrait probablement être
la source
;
c'était une faute de frappe qui n'a pas affecté le problème, ce qui signifie une faute de frappe dans votre question plutôt que dans le code que vous avez réellement utilisé.Les définitions de IN et OUT devraient ressembler à ceci:
Les points-virgules causaient le problème! L'explication est simple: IN et OUT sont des directives de préprocesseur, essentiellement le compilateur remplacera toutes les occurrences de IN par un 1 et toutes les occurrences de OUT par un 0 dans le code source.
Étant donné que le code d'origine avait un point-virgule après le 1 et le 0, lorsque IN et OUT ont été remplacés dans le code, le point-virgule supplémentaire après le numéro a produit un code invalide, par exemple cette ligne:
J'ai fini par ressembler à ceci:
Mais ce que vous vouliez, c'était ceci:
Solution: supprimez le point-virgule après les nombres dans la définition d'origine.
la source
Comme vous le voyez, il y avait un problème dans les macros.
GCC a la possibilité de s'arrêter après le prétraitement.(-E) Cette option est utile pour voir le résultat du prétraitement. En fait, la technique est importante si vous travaillez avec une grande base de code en c / c ++. En général, les makefiles auront une cible à arrêter après le prétraitement.
Pour une référence rapide: La question SO couvre les options - Comment puis-je voir un fichier source C / C ++ après le prétraitement dans Visual Studio? . Il commence par vc ++, mais a également des options gcc mentionnées ci-dessous .
la source
Pas exactement un problème, mais la déclaration de
main()
est également datée, cela devrait ressembler à quelque chose comme ça.Le compilateur supposera une valeur de retour int pour une fonction sans une, et je suis sûr que le compilateur / éditeur de liens contournera le manque de déclaration pour argc / argv et le manque de valeur de retour, mais ils devraient être là.
la source
Essayez d'ajouter des accolades explicites autour des blocs de code. Le style K&R peut être ambigu.
Regardez la ligne 18. Le compilateur vous indique où est le problème.
la source
if
bloc plus tard, si vous oubliez d'ajouter les accolades parce que votre bloc est maintenant plus d'une ligne, cela peut prendre un certain temps pour déboguer cette erreur ...if
clause et d '"oublier" de mettre à jour les accolades alors, eh bien, vous n'êtes pas un très bon programmeur.Un moyen simple consiste à utiliser des crochets comme {} pour chacun
if
etelse
:la source
Comme d'autres réponses l'ont souligné, le problème est entre les
#define
points et les points-virgules. Pour minimiser ces problèmes, je préfère toujours définir les constantes numériques commeconst int
:De cette façon, vous vous débarrassez de nombreux problèmes et problèmes éventuels. Il est limité par seulement deux choses:
Votre compilateur doit prendre en charge
const
- ce qui n'était généralement pas vrai en 1988, mais maintenant il est pris en charge par tous les compilateurs couramment utilisés. (AFAIK leconst
est "emprunté" à C ++.)Vous ne pouvez pas utiliser ces constantes dans certains endroits spéciaux où vous auriez besoin d'une constante de type chaîne. Mais je pense que votre programme n'est pas ce cas.
la source
const int
ne peuvent pas en C.