Deve dichiarare il prototipo di funzione in C?

Sono un po ‘nuovo a C (ho precedenti Java, C # e qualche esperienza C ++). In C, è necessario dichiarare un prototipo di funzione o il codice può essere compilato senza di esso? È buona pratica di programmazione farlo? O dipende solo dal compilatore? (Sto usando Ubuntu 9.10 e uso il compilatore GNU C, o gcc, sotto l’IDE di Code :: Blocks)

In ANSI C (ovvero C89 o C90), non è necessario dichiarare un prototipo di funzione; tuttavia, è una buona pratica usarli. L’unico motivo per cui lo standard ti consente di non utilizzarli è la compatibilità con le versioni precedenti con codice molto vecchio.

Se non si dispone di un prototipo e si chiama una funzione, il compilatore dedurrà un prototipo dai parametri passati alla funzione. Se dichiari la funzione più tardi nella stessa unità di compilazione, otterrai un errore di compilazione se la firma della funzione è diversa da ciò che il compilatore indovina.

Peggio ancora, se la funzione è in un’altra unità di compilazione, non c’è modo di ottenere un errore di compilazione, poiché senza un prototipo non c’è modo di controllare. In tal caso, se il compilatore si sbaglia, si potrebbe ottenere un comportamento indefinito se la chiamata alla funzione spinge diversi tipi nello stack di quanto la funzione si aspetta.

La convenzione è dichiarare sempre un prototipo in un file di intestazione che ha lo stesso nome del file sorgente che contiene la funzione.

In C99 o C11, lo standard C richiede una dichiarazione di funzione nell’ambito prima di chiamare qualsiasi funzione. Molti compilatori non applicano questa restrizione in pratica a meno che non si costringa a farlo.

Non è mai richiesto di dichiarare un prototipo per una funzione in C, né in “vecchio” C (incluso C89 / 90) né in nuovo C (C99). Tuttavia, c’è una differenza significativa tra C89 / 90 e C99 per quanto riguarda le dichiarazioni di funzione.

In C89 / 90 non era necessario dichiarare una funzione. Se la funzione non è dichiarata nel punto della chiamata, il compilatore “indovina” (deduce) la dichiarazione implicitamente dai tipi degli argomenti passati nella chiamata e presuppone che il tipo restituito sia int .

Per esempio

 int main() { int i = foo(5); /* No declaration for `foo`, no prototype for `foo`. Will work in C89/90. Assumes `int foo(int)` */ return 0; } int foo(int i) { return i; } 

In C99 ogni funzione chiamata deve essere dichiarata prima del punto della chiamata. Tuttavia, non è ancora necessario dichiararlo specificamente con un prototipo . Funzionerà anche una dichiarazione non prototipale. Ciò significa che in C99 la regola “implicito int ” non funziona più (per i tipi restituiti di funzione inferita, in questo caso), ma i tipi di parametro possono ancora essere indovinati dai tipi di argomento se la funzione è dichiarata senza un prototipo.

L’esempio precedente non verrà compilato in C99, dato che foo non è dichiarato al punto della chiamata. Tuttavia, è ansible aggiungere una dichiarazione non prototipo

 int foo(); /* Declares `foo`, but still no prototype */ int main() { int i = foo(5); /* No prototype for `foo`, although return type is known. Will work in C99. Assumes `int foo(int)` */ return 0; } ... 

e finiscono con un codice C99 valido.

Tuttavia, è sempre buona norma dichiarare un prototipo per la funzione prima di chiamarla.

Una nota aggiuntiva: ho detto sopra che non è mai richiesto di dichiarare un prototipo di funzione. In effetti, per alcune funzioni è un requisito. Per chiamare correttamente una funzione variadica in C (ad esempio printf ), la funzione deve essere dichiarata con un prototipo prima del punto della chiamata. Altrimenti, il comportamento non è definito. Questo vale sia per C89 / 90 che per C99.

non è un dovere, se la funzione è definita prima del suo utilizzo.

Non è richiesto, ma è una ctriggers pratica non utilizzare i prototipi.

Con i prototipi, il compilatore può verificare che tu stia chiamando correttamente la funzione (usando il giusto numero e tipo di parametri).

Senza prototipi, è ansible avere questo:

 // file1.c void doit(double d) { .... } int sum(int a, int b, int c) { return a + b + c; } 

e questo:

 // file2.c // In C, this is just a declaration and not a prototype void doit(); int sum(); int main(int argc, char *argv[]) { char idea[] = "use prototypes!"; // without the prototype, the compiler will pass a char * // to a function that expects a double doit(idea); // and here without a prototype the compiler allows you to // call a function that is expecting three argument with just // one argument (in the calling function, args b and c will be // random junk) return sum(argc); } 

In C, se non dichiariamo un prototipo di funzione e usiamo la definizione della funzione, non ci sono problemi e il programma compila e genera l’output se il tipo di ritorno della funzione è “intero”. In tutte le altre condizioni appare l’errore del compilatore. Il motivo è che, se chiamiamo una funzione e non dichiariamo un prototipo di funzione, il compilatore genera un prototipo che restituisce un intero e cerca la definizione di funzione simile. se la funzione prototipo corrisponde, viene compilata correttamente. Se il tipo restituito non è intero, i prototipi di funzione non corrispondono e genera un errore. Quindi è meglio dichiarare il prototipo di funzione nei file di intestazione.

C consente di chiamare le funzioni anche se non sono state dichiarate in precedenza, ma ti consiglio vivamente di dichiarare un prototipo per tutte le funzioni prima di usarle in modo che il compilatore possa salvarti se usi gli argomenti sbagliati.

Dovresti inserire le dichiarazioni di funzione nel file di intestazione (Xh) e la definizione nel file di origine (Xc). Quindi altri file possono #include "Xh" e chiamare la funzione.

Il prototipo di funzione non è obbligatorio secondo lo standard C99 .

Non è assolutamente necessario dichiarare una funzione per la compilazione del codice chiamante. Ci sono comunque avvertimenti. Si presume che la funzione non dichiarata restituisca int e il compilatore invierà prima le avvertenze sulla funzione non dichiarata e quindi su eventuali disallineamenti nel tipo restituito e nei tipi di parametro.

Detto questo, è ovvio che dichiarare le funzioni correttamente con i prototipi è una pratica molto migliore.

Seleziona il menu ‘Opzioni’ e quindi seleziona ‘Compilatore | Opzioni C ++ ‘. Nella finestra di dialogo che si apre, seleziona “CPP sempre” nelle opzioni “Usa compilatore C ++”. Ancora una volta selezionare il menu ‘Opzioni’ e quindi selezionare ‘Ambiente | Editor’. Assicurati che l’estensione predefinita sia “C” anziché “CPP”.