Prototipi di funzioni
Una dichiarazione di funzione precede la definizione di funzione e specifica il nome, il tipo restituito, la classe di archiviazione e altri attributi di una funzione. Per essere un prototipo, la dichiarazione della funzione deve inoltre stabilire i tipi e gli identificatori per gli argomenti della funzione.
Sintassi
declaration
:
declaration-specifiers
attribute-seq
opt opt opt init-declarator-list
;
/* attribute-seq
opt è specifico di Microsoft */
declaration-specifiers
:
storage-class-specifier
declaration-specifiers
optare
type-specifier
declaration-specifiers
optare
type-qualifier
declaration-specifiers
optare
init-declarator-list
:
init-declarator
init-declarator-list
,
init-declarator
init-declarator
:
declarator
declarator
=
initializer
declarator
:
pointer
optare direct-declarator
direct-declarator
: /* Dichiaratore di funzione */
direct-declarator
(
parameter-type-list
)
/* Dichiaratore di nuovo stile */
direct-declarator
(
identifier-list
opt )
/* Dichiaratore di stile obsoleto */
Il prototipo ha la stessa forma della definizione della funzione, ad eccezione del fatto che termina con un punto e virgola immediatamente dopo la parentesi di chiusura e pertanto non ha corpo. In entrambi i casi, il tipo restituito deve corrispondere al tipo restituito specificato nella definizione di funzione.
I prototipi di funzione hanno gli utilizzi importanti elencati di seguito:
Stabiliscono il tipo restituito per funzioni che restituiscono tipi diversi da
int
. Anche se le funzioni che restituisconoint
valori non richiedono prototipi, è consigliabile usare prototipi.Senza prototipi completi, le conversioni standard vengono effettuate, ma non viene eseguito alcun tentativo di controllare il tipo o il numero di argomenti con il numero di parametri.
I prototipi sono utilizzati per inizializzare i puntatori a funzioni prima che quelle funzioni vengano definite.
L'elenco di parametri viene usato per verificare che gli argomenti nella chiamata di funzione corrispondano ai parametri nella definizione della funzione.
Il tipo convertito di ogni parametro determina l'interpretazione degli argomenti che la chiamata di funzione inserisce nello stack. Un tipo non corrispondente tra un argomento e un parametro può determinare che gli argomenti nello stack siano interpretati erroneamente. Ad esempio, in un computer a 16 bit, se un puntatore a 16 bit viene passato come argomento, quindi dichiarato come long
parametro, i primi 32 bit nello stack vengono interpretati come long
parametro. Questo errore crea problemi non solo con il long
parametro , ma con tutti i parametri successivi. È possibile rilevare errori di questo tipo dichiarando prototipi di funzione completi per tutte le funzioni.
Un prototipo stabilisce gli attributi di una funzione. Le chiamate di funzione che precedono la definizione della funzione (o che si verificano in altri file di origine) possono quindi essere controllate per verificare la mancata corrispondenza tra tipo di argomento e tipo restituito. Ad esempio, se si specifica l'identificatore static
di classe di archiviazione in un prototipo, è necessario specificare anche la static
classe di archiviazione nella definizione della funzione.
Le dichiarazioni di parametro complete (int a
) possono essere combinate con dichiaratori astratti (int
) nella stessa dichiarazione. Ad esempio, la seguente dichiarazione è valida:
int add( int a, int );
Il prototipo può includere sia il tipo di che un identificatore per ogni espressione passata come argomento. Tuttavia, tali identificatori sono inclusi nell'ambito solo fino alla fine della dichiarazione. Il prototipo può inoltre riflettere il fatto che il numero di argomenti sia variabile o che nessun argomento sia passato. Senza un elenco di questo tipo, le mancate corrispondenze potrebbero non essere rivelate, quindi il compilatore non può generare messaggi di diagnostica relativi. Per altre informazioni sul controllo dei tipi, vedere Argomenti.
L'ambito del prototipo nel compilatore Microsoft C è ora conforme a ANSI durante la compilazione con l'opzione del /Za
compilatore. Se si dichiara un struct
tag o union
all'interno di un prototipo, il tag viene immesso in tale ambito anziché nell'ambito globale. Ad esempio, durante la compilazione con /Za
per la conformità ANSI, non è possibile chiamare questa funzione senza ricevere un errore di mancata corrispondenza del tipo:
void func1( struct S * );
Per correggere il codice, definire o dichiarare o union
nell'ambito struct
globale prima del prototipo della funzione:
struct S;
void func1( struct S * );
In /Ze
il tag viene ancora immesso nell'ambito globale.