2010-10-29 15 views
5

Sto seguendo una guida per imparare le maledizioni e tutto il codice C all'interno delle funzioni dei prototipi prima di main(), quindi le definisco in seguito. Nei miei apprendimenti in C++, avevo sentito parlare della funzione prototipazione ma non l'ho mai fatto, e per quanto ne so non fa troppa differenza sul modo in cui il codice è compilato. È la scelta personale di un programmatore più che altro? Se è così, perché è stato incluso in C?Qual è il punto della prototipazione della funzione?

+4

È necessario inoltrare una dichiarazione quando due funzioni si richiamano. – kennytm

+1

possibile duplicato di [Sono necessari i prototipi per tutte le funzioni in C89, C90 o C99?] (Http://stackoverflow.com/questions/434763/are-prototypes-required-for-all-functions-in-c89-c90- o -99) –

+1

Non vedo perché. Non sto chiedendo se sono necessari, semplicemente non capisco perché sono nello standard in primo luogo. – Maulrus

risposta

3

In C prototipazione è necessario in modo che il programma sa che hai una funzione chiamata x() quando non avete ottenuto a definirla, in questo modo y() sa che c'è ed esiste un x(). C esegue la compilazione top-down, quindi deve essere definito prima che la mano sia la risposta breve.

x(); 
y(); 
main(){ 

} 

y(){ 
x(); 
} 

x(){ 
... 
more code ... 
maybe even y(); 
} 
+1

Penso che questa risposta manchi completamente il punto. Per prima cosa, puoi chiamare qualsiasi funzione anche senza un prototipo in ambito e prima che sia definito (si applicano determinate regole). In secondo luogo, "top down compilation" (qualunque cosa significhi esattamente) non fa parte di C e non c'è alcun obbligo di compilare C in un modo specifico. – Jens

+0

In terzo luogo, il codice snippato non contiene nemmeno prototipi corretti! È così sciatto, 'gcc -Wall -pedantic -std = c89 x.c' produce 10 avvisi. – Jens

0

Consente di avere una situazione in cui si dice che è possibile avere una classe iteratore definita in un file .h separato che include la classe contenitore genitore. Dato che hai incluso l'intestazione genitore nell'iteratore, non puoi avere un metodo come dire "getIterator()" perché il tipo restituito dovrebbe essere la classe iteratore e quindi richiederebbe che tu inserissi l'intestazione iteratore all'interno del intestazione genitore che crea un ciclo ciclico di inclusioni (una include l'altra che include se stessa che include di nuovo l'altra, ecc.).

Se si inserisce il prototipo di classe iteratore nel contenitore padre, è possibile avere un tale metodo senza includere l'intestazione iteratore. Funziona solo perché stai semplicemente dicendo che un tale oggetto esiste e sarà definito.

Ci sono modi per aggirarlo come se avessero un'intestazione precompilata, ma a mio parere è meno elegante e presenta una gran quantità di svantaggi. Di coppia questo è C++, non C. Tuttavia, in pratica potresti avere una situazione in cui ti piacerebbe organizzare il codice in questo modo, a parte le lezioni.

+0

Una classe iteratore, in C? La domanda menziona C++, ma riguarda le razionali C, quindi penso che un altro esempio sia richiesto :-) –

1

Avevo l'impressione che fosse così i clienti potevano accedere al file .h per le librerie e vedere quali funzioni erano disponibili per loro, senza dover vedere l'implementazione (che sarebbe in un altro file).

Utile per vedere cosa restituisce la funzione/quali parametri.

+1

Ottenere le funzioni disponibili dalle intestazioni è una cattiva idea perché le intestazioni potrebbero contenere una magia arbitraria non disponibile per il programmatore dell'applicazione. Uno sviluppatore serio otterrà tutte le informazioni di cui ha bisogno dalla documentazione fornita con le librerie. Per lo standard C, POSIX e molti altri (anche le API di Windows) la documentazione è disponibile gratuitamente e probabilmente già presente (pagine man, aiuto di Windows, ...) Se hai bisogno di raccogliere un prototipo da un'intestazione, sei sul pista sbagliata. – Jens

1

La prototipazione delle funzioni è un residuo dei vecchi tempi della scrittura del compilatore. Era considerato orribilmente inefficiente per un compilatore dover fare più passaggi su un file sorgente per compilarlo.

In C, in determinati contesti, fare riferimento a una funzione in un modo è sintatticamente equivalente al riferimento a una variabile: prendere in considerazione un puntatore a una funzione anziché un puntatore a una variabile. Nella rappresentazione intermedia del compilatore, i due sono semanticamente distinti, ma sintatticamente, se un identificatore è una variabile, un nome di funzione o un identificatore non valido non può essere determinato dal contesto.

Poiché non è determinabile dal contesto, senza i prototipi di funzione, il compilatore dovrebbe eseguire un passaggio aggiuntivo su ciascuno dei file di origine ogni volta che uno di essi viene compilato. Ciò aggiungerebbe un fattore O (n) in più per qualsiasi compilazione (ovvero, se la compilazione fosse O (m), ora sarebbe O (m * n)), dove n è il numero di file nel progetto. Nei progetti di grandi dimensioni, in cui la compilazione è già nell'ordine delle ore, disporre di un compilatore a due passaggi è altamente indesiderabile.

Inoltro dichiarando che tutte le funzioni consentiranno al compilatore di compilare una tabella di funzioni durante la scansione del file e di essere in grado di determinare quando ha rilevato un identificatore indipendentemente dal fatto che si riferisca a una funzione oa una variabile.

Come risultato di ciò, i compilatori C (e per estensione, C++) possono essere estremamente efficienti nella compilazione.

+0

Questo non è necessariamente vero: se non avessero bisogno di prototipi di funzione, non avrebbero dovuto ri-analizzare lo stesso #include trenta volte. Ecco perché le intestazioni precompilate sono così efficaci nel ridurre i tempi di costruzione in MSVC, perché l'inclusione richiede così tanto tempo. – Puppy

+3

Mi piace l'inizio. Sì, il modello di compilazione è la colpa. Ma mi piace molto la difesa di questo modello. Il suggerimento che i compilatori C++ possano essere estremamente efficienti nella compilazione, alla fine è un disastro. Dai! –

11

La prototipazione di funzione originariamente non era inclusa in C. Quando hai chiamato una funzione, il compilatore ha preso la parola per credere che esisterebbe e ha preso il tipo di argomenti che hai fornito. Se hai ottenuto l'argomento ordine, numero o tipo sbagliato, troppo male - il tuo codice fallirebbe, possibilmente in modi misteriosi, in fase di runtime.

Le versioni successive di C hanno aggiunto la funzione di prototipazione per risolvere questi problemi. Gli argomenti vengono convertiti implicitamente in tipi dichiarati in alcune circostanze o contrassegnati come incompatibili con il prototipo e il compilatore potrebbe segnalare come errore l'ordine e il numero di tipi errati. Ciò ha avuto l'effetto collaterale di abilitare le funzioni di vararg e la gestione degli argomenti speciali di cui hanno bisogno.

noti che, in C (ea differenza in C++), una funzione dichiarata foo_t func() non la stessa come una funzione dichiarata come foo_t func(void). Quest'ultimo è prototipato per non avere argomenti. Il primo dichiara una funzione senza un prototipo.

+0

+1 per l'ultima sezione sulla differenza tra una dichiarazione e un prototipo. – legends2k

Problemi correlati