2010-02-18 10 views
5

Cuando mi programa consta de dos archivos:El comportamiento de un compilador C con funciones de estilo antiguo y sin prototipos

MAIN.C

#include <stdio.h> 

int main(void) { 
    printf("%lf\n",f()); 
    return 0; 
} 

func.c

double f(int a) { 
return 1; 
} 

compilador hacer no mostrar ningún error

Cuando mi programa consta de un solo archivo:

main.c

#include <stdio.h> 

int main(void) { 
    printf("%lf\n",f()); 
    return 0; 
} 

double f(int a) { 
return 1; 
} 

Visual C++ 2008 compilador mostrará el siguiente error:

Error 2 error C2371: 'f' : redefinition; different basic types d:\temp\projects\function1\function1\1.c 8 function1 

Puede alguien explicar este comportamiento extraño?

+0

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? –

Respuesta

5

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.

6

C supondrá que una función tiene el prototipo int func(); a menos que lo haya indicado de otra manera. (Tenga en cuenta que en C int func(); int func (void); son cosas diferentes)

En su segundo caso, llame al f() para el cual el compilador no visto cualquier prototipo, por lo que asume que es int f();. Más tarde ve su definición de f() que tiene un prototipo diferente y emite un error.

Esto no ocurre en el caso 1., ya que están en diferentes unidades de compilación.

0

Su primer ejemplo nunca usa func.c, por lo que no estoy seguro de qué está haciendo exactamente el compilador acerca de f() porque no tiene definición.

En el segundo ejemplo, no sé por qué no puede tener dos funciones con firmas diferentes, pero no está llamando a la función que ha definido. Llama al f() sin argumentos, pero el f que define toma un int que lo convierte en una función diferente.

Cuestiones relacionadas