Ambos programas son incorrectos.
Sin un prototipo en el alcance, un compilador asume que una función devuelve int
y toma un número no especificado de parámetros.
Vamos a cambiar sus archivos un poco:
$ cat func.c
double f(int a) {
return 1.0;
}
$ cat main.c
#include <stdio.h>
int main(void) {
double d = f();
printf("%lf\n", d);
return 0;
}
Cuando compilo, gcc me advierte (Visual C++ también debería hacerlo, en el modo conformes). Pero ignoremos la advertencia.
$ gcc -std=c99 -pedantic -W -Wall func.c main.c -o test
func.c:1: warning: unused parameter 'a'
main.c: In function 'main':
main.c:4: warning: implicit declaration of function 'f'
$ ./test
0.000000
No se imprime 1, pero impreso 0. Esto es porque el compilador supone que f()
devolvió un int
, y la asignación d = f();
convertida que "int
" a un double
. El compilador todavía compiló el código porque no podía decir que f()
no se definió de la forma en que se declaró (implícitamente). Pero no es necesario compilar el programa anterior, por lo que el compilador podría haberlo rechazado (¡pruebe con gcc -Werror
, por ejemplo!)
Si tenemos todo en un archivo:
$ cat func.c >>main.c
$ gcc -std=c99 -pedantic -W -Wall func.c main.c -o test
main.c:4: warning: implicit declaration of function 'f'
main.c: At top level:
main.c:9: error: conflicting types for 'f'
main.c:4: error: previous implicit declaration of 'f' was here
main.c:9: warning: unused parameter 'a'
Ahora el compilador ve el conflicto, y le da un mensaje de error. Pero, un compilador no está obligado a rechazar el programa anterior, puede o no.
La mayoría de los compiladores no rechazan el primer programa porque no saben si tiene una definición correcta de la función f()
en otra unidad de traducción o no. Rechazan el segundo programa porque saben que no.
según tengo entendido: en el primer caso, el vinculador es responsable de vincular la llamada de la función con su definición; en el segundo caso, el compilador es responsable de vincular la llamada de la función con su definición. ¿Estoy en lo cierto? –