Tengo este programa simple:
#include <stdio.h>
struct S
{
int i;
};
void swap(struct S *a, struct S *b)
{
struct S temp;
temp = *a /* Oops, missing a semicolon here... */
*a = *b;
*b = temp;
}
int main(void)
{
struct S a = { 1 };
struct S b = { 2 };
swap(&a, &b);
}
Como se ve en, por ejemplo, ideone.com, esto da un error:
prog.c: In function 'swap': prog.c:12:5: error: invalid operands to binary * (have 'struct S' and 'struct S *') *a = *b; ^
¿Por qué el compilador no detecta el punto y coma que falta?
Nota: Esta pregunta y su respuesta están motivadas por esta pregunta . Si bien hay otras preguntas similares a esta, no encontré nada que mencione la capacidad de forma libre del lenguaje C, que es lo que está causando esto y los errores relacionados.
Respuestas:
C es un lenguaje de forma libre . Eso significa que puede formatearlo de muchas maneras y seguirá siendo un programa legal.
Por ejemplo, una declaración como
podría escribirse como
o me gusta
Entonces, cuando el compilador vea las líneas
piensa que significa
Por supuesto, esa no es una expresión válida y el compilador se quejará de eso en lugar del punto y coma que falta. La razón por la que no es válido es porque
a
es un puntero a una estructura, por lo que*a * a
está tratando de multiplicar una instancia de estructura (*a
) con un puntero a una estructura (a
).Si bien el compilador no puede detectar el punto y coma que falta, también informa el error totalmente no relacionado en la línea incorrecta. Es importante notar esto porque no importa cuánto mire la línea donde se informa el error, no hay ningún error allí. A veces, problemas como este necesitarán que mire las líneas anteriores para ver si están bien y sin errores.
A veces, incluso tiene que buscar en otro archivo para encontrar el error. Por ejemplo, si un archivo de encabezado está definiendo una estructura lo último que lo hace en el archivo de encabezado, y falta el punto y coma que termina la estructura, entonces el error no estará en el archivo de encabezado sino en el archivo que incluye el archivo de encabezado.
Y a veces las cosas empeoran aún más: si incluye dos (o más) archivos de encabezado y el primero contiene una declaración incompleta, lo más probable es que el error de sintaxis se indique en el segundo archivo de encabezado.
Relacionado con esto está el concepto de errores de seguimiento . Algunos errores, generalmente debido a que faltan puntos y comas, se informan como errores múltiples . Por eso es importante comenzar desde arriba al corregir errores, ya que corregir el primer error puede hacer que desaparezcan varios errores.
Por supuesto, esto puede llevar a corregir un error a la vez y a recompilaciones frecuentes que pueden resultar engorrosas con proyectos grandes. Sin embargo, reconocer estos errores de seguimiento es algo que viene con la experiencia, y después de verlos varias veces, es más fácil descubrir los errores reales y corregir más de un error por recompilación.
fuente
temp = *a * a = *b
podría ser una expresión válida sioperator*
estuviera sobrecargado. (Sin embargo, la pregunta está etiquetada como "C".)Hay tres cosas que recordar.
*
en C puede ser un operador unario y binario. Como operador unario significa "desreferencia", como operador binario significa "multiplicar".El resultado de estos dos hechos es cuando analizamos.
El primero y el último
*
se interpretan como unario, pero el segundo*
se interpreta como binario. Desde una perspectiva de sintaxis, esto parece correcto.Solo después de analizar cuando el compilador intenta interpretar los operadores en el contexto de sus tipos de operandos, se ve un error.
fuente
Algunas buenas respuestas arriba, pero las detallaré.
Este es en realidad un caso
x = y = z;
en el que a ambosx
y sey
les asigna el valor dez
.Lo que estás diciendo es
the contents of address (a times a) become equal to the contents of b, as does temp
.En resumen,
*a *a = <any integer value>
es una afirmación válida. Como se señaló anteriormente, el primero*
elimina la referencia a un puntero, mientras que el segundo multiplica dos valores.fuente
y
ni siquiera es una variable, es la expresión*a *a
y no se puede asignar al resultado de una multiplicación.La mayoría de los compiladores analizan los archivos fuente en orden e informan la línea donde descubren que algo andaba mal. Las primeras 12 líneas de su programa C podrían ser el inicio de un programa C válido (sin errores). Las primeras 13 líneas de su programa no pueden. Algunos compiladores notarán la ubicación de las cosas que encuentran que no son errores en sí mismos y, en la mayoría de los casos, no desencadenarán errores más adelante en el código, pero es posible que no sean válidos en combinación con otra cosa. Por ejemplo:
La declaración
int foo;
por sí sola estaría perfectamente bien. Asimismo la declaraciónfloat foo;
. Algunos compiladores pueden registrar el número de línea donde apareció la primera declaración y asociar un mensaje informativo con esa línea, para ayudar al programador a identificar los casos en los que la definición anterior es en realidad la errónea. Los compiladores también pueden mantener los números de línea asociados con algo como ado
, que se puede informar si el asociadowhile
no aparece en el lugar correcto. Sin embargo, para los casos en los que la ubicación probable del problema sería inmediatamente anterior a la línea donde se descubre el error, los compiladores generalmente no se molestan en agregar un informe adicional para la posición.fuente