Estou tentando compilar este pedaço de código do livro "The C Programming Language" (K & R). É uma versão básica do programa UNIXwc
:
#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);
}
E estou recebendo o seguinte erro:
$ gcc wc.c
wc.c: In function ‘main’:
wc.c:18: error: ‘else’ without a previous ‘if’
wc.c:18: error: expected ‘)’ before ‘;’ token
A 2ª edição deste livro é de 1988 e sou muito novo em C. Talvez tenha a ver com a versão do compilador ou talvez eu esteja apenas falando bobagem.
Eu vi no código C moderno um uso diferente da main
função:
int main()
{
/* code */
return 0;
}
Este é um novo padrão ou ainda posso usar um principal sem tipo?
|| c = '\t')
. Parece igual ao outro código dessa linha?Respostas:
Seu problema é com as definições do pré-processador de
IN
eOUT
:Observe como você tem um ponto e vírgula final em cada um deles. Quando o pré-processador os expandir, seu código se parecerá com:
Esse segundo ponto-e-vírgula faz
else
com que o não tenha anteriorif
como uma correspondência, porque você não está usando colchetes. Portanto, remova os pontos-e-vírgulas das definições do pré-processador deIN
eOUT
.A lição aprendida aqui é que as instruções do pré-processador não precisam terminar com um ponto-e-vírgula.
Além disso, você deve sempre usar aparelho!
Não há
else
ambigüidade suspensa no código acima.fonte
O principal problema com este código é que ele é não o código da K & R. Inclui ponto e vírgula após as definições de macros, que não estavam presentes no livro, que, como outros apontaram, muda o significado.
Exceto ao fazer uma alteração na tentativa de entender o código, você deve deixá-lo sozinho até entendê-lo. Você só pode modificar com segurança o código que você entende.
Provavelmente foi apenas um erro de digitação de sua parte, mas ilustra a necessidade de compreensão e atenção aos detalhes durante a programação.
fonte
Não deve haver ponto-e-vírgula após as macros,
e provavelmente deveria ser
fonte
;
era um erro de digitação que não afetou o problema, o que significa um erro de digitação na sua pergunta, e não no código que você realmente usou.As definições de IN e OUT devem ser assim:
Os pontos-e-vírgulas estavam causando o problema! A explicação é simples: tanto IN quanto OUT são diretivas de pré-processador, essencialmente o compilador irá substituir todas as ocorrências de IN por 1 e todas as ocorrências de OUT por 0 no código-fonte.
Como o código original tinha um ponto-e-vírgula após o 1 e o 0, quando IN e OUT foram substituídos no código, o ponto-e-vírgula extra após o número produziu um código inválido, por exemplo esta linha:
Acabou ficando assim:
Mas o que você queria era isso:
Solução: remova o ponto-e-vírgula após os números na definição original.
fonte
Como você pode ver, houve um problema nas macros.
O GCC tem a opção de parar após o pré-processamento. (-E) Esta opção é útil para ver o resultado do pré-processamento. Na verdade, a técnica é importante se você estiver trabalhando com uma grande base de código em c / c ++. Normalmente, os makefiles terão um destino para parar após o pré-processamento.
Para referência rápida: A questão do SO cobre as opções - Como vejo um arquivo de origem C / C ++ após o pré-processamento no Visual Studio? . Ele começa com vc ++, mas também tem opções gcc mencionadas abaixo .
fonte
Não é exatamente um problema, mas a declaração de
main()
também está datada, deveria ser algo assim.O compilador assumirá um valor de retorno interno para uma função sem uma, e tenho certeza que o compilador / vinculador irá contornar a falta de declaração para argc / argv e a falta de valor de retorno, mas eles deveriam estar lá.
fonte
Tente adicionar chaves explícitas ao redor dos blocos de código. O estilo K&R pode ser ambíguo.
Observe a linha 18. O compilador está informando onde está o problema.
fonte
if
bloco mais tarde, se você esquecer de adicionar as chaves porque o seu bloco agora é mais de uma linha, pode demorar um pouco para depurar esse erro ...if
cláusula e "esquecer" de atualizar as chaves, então, bem, você não um programador muito bom.Uma maneira simples é usar colchetes como {} para cada um
if
eelse
:fonte
Como outras respostas apontaram, o problema está entre
#define
e ponto e vírgula. Para minimizar esses problemas, sempre prefiro definir constantes numéricas comoconst int
:Desta forma, você se livra de muitos problemas e possíveis problemas. É limitado por apenas duas coisas:
Seu compilador tem que oferecer suporte
const
- o que em 1988 geralmente não era verdade, mas agora é suportado por todos os compiladores comumente usados. (AFAIK, oconst
é "emprestado" do C ++.)Você não pode usar essas constantes em alguns lugares especiais onde precisaria de uma constante semelhante a uma string. Mas acho que seu programa não é esse o caso.
fonte
const int
não podem em C.