name keywords etiquetas etiqueta ejemplos c

c - keywords - meta tags seo



¿Qué pasa con este código C de 1988? (9)

Como señalaron otras respuestas, el problema está en #define y punto y coma. Para minimizar estos problemas, siempre prefiero definir las constantes numéricas como un const int :

const int IN = 1; const int OUT = 0;

De esta forma puedes deshacerte de muchos problemas y posibles problemas. Está limitado solo por dos cosas:

  1. Su compilador debe ser compatible con const , que en 1988 no era cierto en general, pero ahora es compatible con todos los compiladores comúnmente utilizados. (AFAIK la const es "prestada" de C ++)

  2. No puede usar estas constantes en algunos lugares especiales donde necesitaría una constante tipo cadena. Pero creo que su programa no es ese caso.

Estoy tratando de compilar este fragmento de código del libro "The C Programming Language" (K & R). Es una versión escueta del programa wc UNIX:

#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 para C. Tal vez tiene que ver con la versión del compilador o tal vez estoy hablando tonterías.

He visto en el moderno código C un uso diferente de la función main :

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

¿Es este un nuevo estándar o puedo seguir usando un main sin tipo?


Como ve, había 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 gran base de código 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 mencionadas a continuación .


El principal problema con este código es que no es el código de K & R. Incluye puntos y comas después de las definiciones de las macros, que no estaban presentes en el libro, que como otros señalaron, cambia el significado.

Excepto cuando realice un cambio en un intento de comprender el código, debe dejarlo en paz hasta que lo comprenda. Solo puedes modificar el código que entiendes de forma segura.

Probablemente fue solo un error de tu parte, pero ilustra la necesidad de comprensión y atención a los detalles cuando se programa.


Intente agregar llaves explícitas alrededor de los bloques de código. El estilo de K & R puede ser ambiguo.

Mira la línea 18. El compilador te dice dónde está el problema.

if (c == ''/n'') { ++nl; } if (c == '' '' || c == ''/n'' || c == ''/t'') { // You''re missing an "=" here; should be "==" state = OUT; } else if (state == OUT) { state = IN; ++nw; }


Las definiciones de IN y OUT deberían verse así:

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

¡El punto y coma estaba causando el problema! La explicación es simple: tanto IN como OUT son directivas de preprocesador, esencialmente el compilador reemplazará todas las ocurrencias de IN con un 1 y todas las ocurrencias de OUT con un 0 en el código fuente.

Como el código original tenía un punto y coma después de 1 y 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:

else if (state == OUT)

Terminó luciendo así:

else if (state == 0;)

Pero lo que querías era esto:

else if (state == 0)

Solución: elimine el punto y coma después de los números en la definición original.


No debería haber ningún punto y coma después de las macros,

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

y probablemente debería ser

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


No es exactamente un problema, pero la declaración de main() también está fechada, debería ser algo así.

int main(int argc, char** argv) { ... return 0; }

El compilador asumirá un valor de retorno int para una función sin / o, y estoy seguro de que el compilador / enlazador funcionará en torno a la falta de declaración para argc / argv y la falta de valor de retorno, pero deberían estar allí.


Su problema es con sus definiciones de preprocesador de IN y OUT :

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

Observe cómo tiene un punto y coma final en cada uno de estos. Cuando el preprocesador los expanda, su código se verá más o menos así:

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

Ese segundo punto y coma hace que el else no tenga una coincidencia anterior, porque no está usando llaves. Por lo tanto, elimine los puntos y comas de las definiciones del preprocesador de IN y OUT .

La lección aprendida aquí es que las declaraciones de preprocesador no tienen que terminar con un punto y coma.

Además, siempre debes usar llaves.

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

No hay ambigüedad colgante en el código anterior.


Una forma simple es usar corchetes como {} para cada if y else :

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