2010-02-18 8 views
5

Quando il mio programma è costituito da due file:Il comportamento di un compilatore C con funzioni di vecchio stile, senza prototipi

main.c

#include <stdio.h> 

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

func.c

double f(int a) { 
return 1; 
} 

compilatore fare non mostrare errori.

Quando il mio programma si compone di un solo file:

main.c

#include <stdio.h> 

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

double f(int a) { 
return 1; 
} 

Visual C++ 2008 compilatore mostrerà il seguente errore:

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

Qualcuno può spiegare questo strano comportamento?

+0

come ho capito: nel primo caso il linker è responsabile per l'associazione della chiamata della funzione con la sua definizione; nel secondo caso il compilatore è responsabile per l'associazione della chiamata della funzione con la sua definizione. Ho ragione? –

risposta

5

Entrambi i programmi sono errati.

Senza un prototipo in ambito, un compilatore presuppone che una funzione restituisca int e utilizzi un numero non specificato di parametri.

Cambiamo i file un po ':

$ 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; 
} 

Quando compilo che, gcc mi avverte (Visual C++ dovrebbe troppo, in modo conforme). Ma ignoriamo l'avvertimento.

$ 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 

E non è stato stampato 1, ma stampato 0. Questo è perché il compilatore presume che f() restituito un int, e l'assegnazione d = f(); convertito che "int" ad un double. Il compilatore ha ancora compilato il codice perché non è stato possibile stabilire che f() non è stato definito come dichiarato (implicitamente). Ma la compilazione del programma di cui sopra non è richiesta dallo standard, quindi il compilatore potrebbe averlo respinto (prova con gcc -Werror per esempio!)

Se abbiamo tutto in un unico file:

$ 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' 

Ora il compilatore vede il conflitto, e ti dà un messaggio di errore. Ma un compilatore non è tenuto a rifiutare il programma di cui sopra, può o non può.

La maggior parte dei compilatori non rifiuta il primo programma perché non sa se si ha una definizione corretta della funzione f() in un'altra unità di traduzione o meno. Rifiutano il secondo programma perché lo sa che non lo si fa.

6

C assumerà una funzione ha il prototipo int func(); a meno che non l'abbia detto diversamente. (Si noti che in C int func() e int func (void) sono cose diverse)

Nel secondo caso, si effettua una chiamata a f() per cui il compilatore non ha visto qualsiasi prototipo, quindi si presume che sia int f();. Successivamente vedrà la tua definizione per f() che ha un prototipo diverso e genera un errore.

Ciò non accade nel caso 1., poiché si trovano in diverse unità di compilazione.

0

Il tuo primo esempio non utilizza mai func.c quindi non sono sicuro di cosa stia facendo esattamente il compilatore su f() perché non ha una definizione.

Nel secondo esempio, non so perché non è possibile avere due funzioni con firme diverse, ma non si sta chiamando la funzione definita. Chiami f() senza argomenti, ma lo f che tu definisci prende un int che lo rende una funzione diversa.