Estoy intentando compilar este código del libro "El lenguaje de programación C" (K & R). Es una versión básica del programa 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);
}
Y recibo el siguiente error:
$ 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 segunda edición de este libro es de 1988 y soy bastante nuevo en C. Tal vez tenga que ver con la versión del compilador o tal vez solo estoy diciendo tonterías.
He visto en el código C moderno un uso diferente de la main
función:
int main()
{
/* code */
return 0;
}
¿Es este un nuevo estándar o todavía puedo usar un main sin tipo?
|| c = '\t')
. ¿Parece lo mismo que el otro código en esa línea?Respuestas:
Su problema es con las definiciones de su preprocesador de
IN
yOUT
:Observe cómo tiene un punto y coma al final en cada uno de estos. Cuando el preprocesador los expande, su código se verá más o menos como:
Ese segundo punto y coma hace
else
que no tenga un anteriorif
como coincidencia, porque no está usando llaves. Por lo tanto, elimine el punto y coma de las definiciones del preprocesador deIN
yOUT
.La lección aprendida aquí es que las declaraciones del preprocesador no tienen que terminar con un punto y coma.
Además, ¡siempre debes usar aparatos ortopédicos!
No hay
else
ambigüedad pendiente en el código anterior.fuente
El principal problema con este código es que es no el código de K & R. Incluye punto y coma después de las definiciones de macros, que no estaban presentes en el libro, que como otros han señalado cambia el significado.
Excepto cuando haga un cambio en un intento de comprender el código, debe dejarlo solo hasta que lo comprenda. Solo puede modificar de forma segura el código que comprenda.
Esto probablemente fue solo un error tipográfico de su parte, pero ilustra la necesidad de comprender y prestar atención a los detalles al programar.
fuente
No debe haber punto y coma después de las macros,
y probablemente debería ser
fuente
;
era un error tipográfico que no afectó el problema, lo que significa un error tipográfico en tu pregunta en lugar del código que realmente usaste.Las definiciones de IN y OUT deberían verse así:
¡Los puntos y comas estaban causando el problema! La explicación es simple: tanto IN como OUT son directivas de preprocesador, esencialmente el compilador reemplazará todas las apariciones de IN con un 1 y todas las apariciones de OUT con un 0 en el código fuente.
Dado que el código original tenía un punto y coma después del 1 y el 0, cuando IN y OUT se reemplazaron en el código, el punto y coma adicional después del número produjo un código no válido, por ejemplo, esta línea:
Terminó luciendo así:
Pero lo que querías era esto:
Solución: elimine el punto y coma después de los números en la definición original.
fuente
Como ve, hubo un problema en las macros.
GCC tiene la opción de detenerse después del preprocesamiento. (-E) Esta opción es útil para ver el resultado del preprocesamiento. De hecho, la técnica es importante si está trabajando con una base de código grande en c / c ++. Normalmente, los archivos MAKE tendrán un objetivo para detenerse después del preprocesamiento.
Para una referencia rápida: La pregunta SO cubre las opciones: ¿Cómo veo un archivo fuente C / C ++ después del preprocesamiento en Visual Studio? . Comienza con vc ++, pero también tiene las opciones de gcc que se mencionan a continuación .
fuente
No es exactamente un problema, pero la declaración de
main()
también está fechada, debería ser algo así.El compilador asumirá un valor de retorno int para una función sin uno, y estoy seguro de que el compilador / enlazador solucionará la falta de declaración para argc / argv y la falta de valor de retorno, pero deberían estar ahí.
fuente
Intente agregar llaves explícitas alrededor de bloques de código. El estilo de K&R puede ser ambiguo.
Mire la línea 18. El compilador le dice dónde está el problema.
fuente
if
bloque más adelante, si olvida agregar las llaves porque su bloque ahora tiene más de una línea, puede tomar un tiempo depurar ese error ...if
cláusula y "olvidar" actualizar las llaves, entonces, bueno, no lo eres un muy buen programador.Una forma sencilla es usar corchetes como {} para cada uno
if
yelse
:fuente
Como señalaron otras respuestas, el problema está en
#define
punto y coma. Para minimizar estos problemas, siempre prefiero definir las constantes numéricas comoconst int
:De esta forma te deshaces de muchos problemas y posibles problemas. Está limitado por solo dos cosas:
Su compilador tiene que ser compatible
const
, lo que en 1988 no era cierto en general, pero ahora es compatible con todos los compiladores de uso común. (AFAIK elconst
es "prestado" de C ++.)No puede usar estas constantes en algunos lugares especiales donde necesitaría una constante similar a una cadena. Pero creo que su programa no es ese caso.
fuente
const int
no pueden en C.