Classi di Storage per le Funzioni in Linguaggio C
In linguaggio C, le dichiarazioni e le definizioni di una funzione possono includere anche le classi di storage, analogamente al caso delle variabili.
Tuttavia, a differenza del caso delle variabili, le funzioni possono avere soltanto le classi extern e static.
In questa lezione studieremo queste due opzioni per le funzioni.
Funzioni dichiarate come extern
Una funzione in linguaggio C può essere dichiarata con la classe di storage extern. La sintassi è la seguente:
extern tipo_di_ritorno nome_funzione(parametri);
Quando dichiariamo una funzione con extern stiamo dicendo che il suo linkage è esterno, in altre parole, quella funzione può essere chiamata da altri file sorgente.
Dichiarare una funzione come extern è ridondante in quanto tutte le funzioni sono di default extern. Tuttavia, è possibile dichiarare una funzione come extern per chiarire che la funzione è definita in un altro file sorgente.
Per cui, le seguenti definizioni sono equivalenti:
int somma(int a, int b);
extern int somma(int a, int b);
Ricapitolando:
Funzioni dichiarate come extern
Una funzione dichiarata come extern ha linkage esterno, ossia può essere richiamata da altri file sorgenti differenti da quello in cui è definita.
La sintassi è la seguente:
extern tipo_di_ritorno nome_funzione(parametri);
Tutte le funzioni sono di default extern per cui dichiarare una funzione come extern è ridondante.
Funzioni dichiarate come static
Dichiarare una funzione come static ha un significato diverso rispetto al caso delle variabili.
Una funzione dichiarata come static ha linkage interno, ossia può essere chiamata soltanto all'interno del file sorgente in cui è definita. Ad esempio:
static int somma(int a, int b) {
return a + b;
}
In questo caso, la funzione somma può essere chiamata soltanto all'interno del file sorgente in cui è definita. Se si tenta di chiamare somma da un altro file sorgente, il compilatore restituirà un errore.
Dichiarare una funzione come static non previene del tutto la possibilità di invocare una funzione da un altro file sorgente. Risulta sempre possibile, infatti, utilizzare un puntatore a funzione per farlo.
In ogni caso, l'utilizzo di static per le funzioni ha tutta una serie di vantaggi:
-
Facilità di Manutenzione:
Quando dichiariamo una funzione
staticabbiamo la garanzia che la funzione non è visibile al di fuori del file sorgente. Pertanto, se dobbiamo modificare la funzione, possiamo farlo senza preoccuparci di eventuali effetti collaterali su altri file sorgente. -
Riduzione di possibili Name Clash:
Un Name Clash, che possiamo tradurre in italiano come conflitto di nomi, si verifica quando due funzioni con lo stesso nome sono definite in due file sorgente differenti.
Se dichiariamo una funzione
static, dal momento che non è visibile al di fuori, ne possiamo riutilizzare il nome per definire un'altra funzione in un altro file sorgente purché anch'essa sia dichiarata comestatic.Questo è particolarmente utile in programmi di grandi dimensioni che, possibilmente, sono sviluppati da più programmatori. Oppure quando andiamo ad utilizzare librerie scritte da terzi. Potrebbe capitare, ad esempio, che una libreria fornisca una funzione con un nome che noi abbiamo già utilizzato. Se dichiariamo la nostra funzione come
static, possiamo evitare il conflitto di nomi.Quando l'insieme delle funzioni che compongono un programma è grande, è facile che si verifichino conflitti di nomi o che comunque si debba fare attenzione a non utilizzare nomi già utilizzati da altre funzioni. In gergo tecnico si parla di Namespace Pollution, o Inquinamento dello spazio dei nomi. Si tratta di un fenomeno molto sentito nella programmazione in C, in cui non esiste un vero e proprio meccanismo di namespace come in altri linguaggi di programmazione.
In C++, invece, questo problema è stato risolto introducendo il concetto di namespace.
Ricapitolando:
Funzioni dichiarate come static
Una funzione dichiarata come static ha linkage interno, ossia può essere chiamata soltanto all'interno del file sorgente in cui è definita.
La sintassi è la seguente:
static tipo_di_ritorno nome_funzione(parametri);
Dichiarare una funzione come static previene la possibilità di chiamarla da altri file sorgente. Tuttavia, è sempre possibile farlo utilizzando un puntatore a funzione.
Classi di storage per i parametri di una funzione
Chiudiamo questa lezione con un ultimo chiarimento riguardo alle classi di storage per i parametri di una funzione.
A differenza delle variabili normali, i parametri di una funzione possono avere solo due classi di storage:
-
autocome le variabili automatiche:Dal momento che
autoè ridondante, non viene mai utilizzato per i parametri di una funzione. -
register:I parametri di una funzione possono essere dichiarati come
registerper indicare al compilatore che il parametro verrà utilizzato frequentemente e che quindi è conveniente memorizzarlo in un registro del processore.Tuttavia, il compilatore non è obbligato a rispettare questa indicazione. Se non ci sono registri disponibili, il parametro verrà memorizzato in memoria. Proprio come nel caso delle variabili.
Altre classi di storage non sono consentite.
In Sintesi
- Le funzioni in linguaggio C possono avere le classi di storage
externestatic. - Una funzione dichiarata come
externha linkage esterno e può essere chiamata da altri file sorgente. - La classe
externè quella di default per le funzioni. - Una funzione dichiarata come
staticha linkage interno e può essere chiamata soltanto all'interno del file sorgente in cui è definita. - Dichiarare una funzione come
staticpreviene la possibilità di chiamarla da altri file sorgente. - Tuttavia è sempre possibile farlo utilizzando un puntatore a funzione.
- Le funzioni possono avere solo due classi di storage per i parametri:
autoeregister.
Nella prossima lezione metteremo insieme tutto quello che abbiamo imparato sulle classi di storage per le variabili e per le funzioni fornendo un quadro riepilogativo.