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:

Definizione

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 static abbiamo 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 come static.

    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:

Definizione

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:

  • auto come 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 register per 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 extern e static.
  • Una funzione dichiarata come extern ha linkage esterno e può essere chiamata da altri file sorgente.
  • La classe extern è quella di default per le funzioni.
  • Una funzione dichiarata come static ha linkage interno e può essere chiamata soltanto all'interno del file sorgente in cui è definita.
  • Dichiarare una funzione come static previene 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: auto e register.

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.