Con questo codice:Domande su Prototipi C funzione e compilazione
int main(){
printf("%f\n",multiply(2));
return 0;
}
float multiply(float n){
return n * 2;
}
Quando provo a compilare ottengo un avvertimento: " '% f' aspetta 'doppio', ma l'argomento è di tipo 'int'" e due errori: "i tipi in conflitto per" moltiplicare "", "la dichiarazione implicita precedente di" moltiplicare "era qui."
Domanda 1: Sto indovinando che è perché, dato il compilatore non è a conoscenza della funzione di 'moltiplicare' quando si imbatte per la prima volta, si inventerà un prototipo, e inventò prototipi assumo sempre 'int' viene restituito e preso come parametro. Quindi il prototipo inventato sarebbe "int moltiplicare (int)", e quindi gli errori. È corretto?
Ora, il codice precedente non verrà compilato. Tuttavia, se rompo il codice in due file in questo modo:
#file1.c
int main(){
printf("%f\n",multiply(2));
return 0;
}
#file2.c
float multiply(float n){
return n * 2;
}
ed eseguire "gcc file1.c file2.c -o file" sarà ancora dare un avvertimento (che è in attesa di printf doppia, ma è sempre int) ma gli errori non verranno più visualizzati e verranno compilati.
Domanda 2: Come mai quando rompo il codice in 2 file che compila?
Domanda 3: Una volta eseguito il programma sopra (la versione divisa in 2 file), il risultato è che 0.0000 è stampato sullo schermo. Come mai? Immagino che il compilatore abbia inventato di nuovo un prototipo che non corrisponde alla funzione, ma perché viene stampato 0? E se cambio il printf ("% f") in printf ("% d") stampa un 1. Ancora una spiegazione di cosa sta succedendo dietro le quinte?
Grazie mille in anticipo.
Ha senso. L'unico punto ancora non chiaro è il motivo per cui il compilatore non troverà la menzogna/contraddizione con 2 file. Dopotutto continuerà a creare il prototipo "int multiply (int)" mentre è in esecuzione attraverso main.c, e una volta arrivato al secondo file troverà la dichiarazione di funzione "float multiply (float)", che contraddice chiaramente il precedente prototipo. –
@DanielS Buon punto! Ho modificato la risposta per citare il motivo: in sostanza, il compilatore compila ogni file separatamente, una fonte alla volta. Questo è diverso, ad esempio, da Java, che considera tutti i file contemporaneamente. Con C e C++, ogni unità di traduzione (che è un nome di fantasia per un file '.c') viene compilata separatamente, quindi il linker riunisce i risultati insieme. Nel momento in cui il linker entra in gioco, tuttavia, tutte le informazioni sul tipo sono scomparse: i linker funzionano su un livello molto più basso di byte, offset e indirizzi, quindi non possono nemmeno rilevare una discrepanza. – dasblinkenlight
@DanielS: il compilatore funziona con un file alla volta; mentre lavora su 'file1.c', non sa nulla dei contenuti di' file2.c' e viceversa. Quando si costruisce 'file1.c', sa solo che' multiply' non è stato dichiarato prima dell'uso. Quando si costruisce 'file2.c', non si sa che' moltiplicare' viene utilizzato in un'altra unità di traduzione senza una dichiarazione appropriata nell'ambito. –