94 votes

Quel est le problème avec ce code C 1988?

Je suis en train de compiler ce morceau de code dans le livre "the C Programming Language" (K & R). Il est un nu-os version 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 2e édition de ce livre est de 1988 et je suis assez nouveau à C. Peut-être que cela a à voir avec la version de compilateur ou peut-être je suis juste de dire des sottises.

J'ai vu dans moderne le code C d'un usage différent de l' main fonction de:

int main() {
    /* code */
    return 0;
}

Est-ce une nouvelle norme ou puis-je toujours utiliser un type moins de main?

247voto

user7116 Points 39829

Votre problème est avec votre définitions de préprocesseur IN et OUT:

#define IN   1;     /* inside a word */
#define OUT  0;     /* outside a word */

Remarquez comment vous vous avez un point-virgule de fin dans chacun de ces. Lorsque le préprocesseur se développe, votre code ressemblera à peu près à:

    if (c == ' ' || c == '\n' || c == '\t')
        state = 0;; /* <--PROBLEM #1 */
    else if (state == 0;) { /* <--PROBLEM #2 */
        state = 1;;

Ce deuxième point-virgule fait l' else n'ont aucun précédent if comme un match, parce que vous n'êtes pas en utilisant des accolades. Donc, supprimer le point-virgule de la définitions de préprocesseur IN et OUT.

La leçon à retenir ici est que le préprocesseur états n'ont pas de terminer par un point-virgule.

Aussi, vous devez toujours utiliser des accolades!

    if (c == ' ' || c == '\n' || c == '\t') {
        state = OUT;
    } else if (state == OUT) {
        state = IN;
        ++nw;
    }

Il n'y a pas de pendaison-else ambiguïté dans le code ci-dessus.

63voto

jmoreno Points 6995

Le principal problème avec ce code, c'est que c'est pas le code de la K&R. Il comprend des points-virgules après les définitions de macros, qui n'étaient pas présents dans le livre, qui comme d'autres l'ont souligné les changements de sens.

Sauf lors d'un changement dans une tentative de comprendre le code, vous devez le laisser seul jusqu'à ce que vous le faire comprendre. Vous ne pouvez en toute sécurité modifier le code vous comprendre.

Ce fut probablement une erreur de frappe de votre part, mais elle illustre la nécessité pour la compréhension et l'attention aux détails lors de la programmation.

34voto

onemach Points 1735

Il ne devrait pas y avoir de point-virgule après les macros,

 #define IN   1     /* inside a word */
#define OUT  0     /* outside a word */
 

et il devrait probablement être

 if (c == ' ' || c == '\n' || c == '\t')
 

24voto

Óscar López Points 97105

Les définitions de DANS et devrait ressembler à ceci:

#define IN   1     /* inside a word  */
#define OUT  0     /* outside a word */

Les points-virgules ont été à l'origine du problème! L'explication est simple: à la fois DANS et à l'extérieur sont les directives de préprocesseur, essentiellement le compilateur remplace toutes les occurrences de 1 et de toutes les occurrences de SORTIR avec un 0 dans le code source.

Depuis le code d'origine avait un point-virgule après le 1 et le 0, DANS et HORS obtenu remplacé dans le code, le supplément de point-virgule après le numéro de produit code non valide, par exemple cette ligne:

else if (state == OUT)

Fini par ressembler à ceci:

else if (state == 0;)

Mais ce que vous voulais, c'était ceci:

else if (state == 0)

Solution: supprimez le point-virgule après les chiffres dans la définition d'origine.

8voto

Jayan Points 7171

Comme vous le voyez il y a 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 de pré-traitement. En fait, la technique est importante si vous travaillez avec des grands de la base de code en c/c++. Généralement les makefiles aura une cible pour s'arrêter après le pré-traitement.

Pour une référence rapide : c'est La question couvre les options -- C/C++ source file après prétraitement. Il commence avec vc++, mais a également des options de gcc mentionné vers le bas ci-dessous.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X