Nel linguaggio C, i prototipi di funzione (function prototypes) sono dichiarazioni di funzioni che informano il compilatore sul tipo di ritorno, il nome e i tipi dei parametri della funzione prima della sua effettiva implementazione. I prototipi sono solitamente collocati in file di intestazione (.h). Il loro utilizzo consente di:
Esempio di prototipo:
// math_utils.h int sum(int a, int b); // Prototipo della funzione
// main.c #include "math_utils.h" int main() { int result = sum(3, 4); // il compilatore conosce la firma di sum }
Senza il prototipo, la funzione verrebbe vista come che restituisce int e accetta un numero indefinito di argomenti, il che può portare a errori imprevisti a runtime.
Domanda: È possibile chiamare una funzione in C prima della sua definizione, se non è dichiarata come prototipo?
Risposta: Nello standard C89 era consentito chiamare funzioni prima della loro definizione, se il valore di ritorno era int e i parametri non venivano controllati (implicit int, implicit promotion). Negli standard moderni questo porta a avvertimenti o errori, e non dovrebbero essere seguiti tali approcci.
Esempio di errore:
int main() { foo(1, 2); // Nessun prototipo foo } int foo(double x, double y) { ... }
Il compilatore chiamerà la funzione, considerando i parametri come int, anche se la firma implica double — risultato: UB o valori errati.
Storia
In un grande progetto scientifico, in uno dei moduli mancavano i prototipi per le funzioni di elaborazione dei dati. Passando
floatinvece diint, gli errori sono stati individuati solo dopo calcoli errati in fase di utilizzo, anche se la compilazione è avvenuta senza errori.
Storia
In un'utilità modulare di automazione della build, le funzioni erano definite solo in file
.c, senza dichiarazioni nei file di intestazione. In due moduli erano state definite funzioni con lo stesso nome e parametri incompatibili — ha portato a un errore di collegamento difficile da individuare.
Storia
In un progetto per un sistema embedded, è sorto un problema: la funzione di inizializzazione veniva chiamata prima della sua definizione senza prototipo. A causa dell'assunzione del compilatore sui tipi dei parametri e di ritorno, la logica era gravemente compromessa e il sistema si bloccava solo in determinate build con diversa organizzazione della memoria.