6.7.4 specificatori di funzione
Una nuova funzionalità di C99: la inline
parola chiave, adattata da C ++, è un identificatore di funzione che può essere utilizzato solo nelle dichiarazioni di funzione. È utile per le ottimizzazioni del programma che richiedono che la definizione di una funzione sia visibile nel sito di una chiamata. (Si noti che lo Standard non cerca di specificare la natura di queste ottimizzazioni.)
La visibilità è assicurata se la funzione ha un collegamento interno o se ha un collegamento esterno e la chiamata si trova nella stessa unità di traduzione della definizione esterna. In questi casi, la presenza della
inline
parola chiave in una dichiarazione o definizione della funzione non ha alcun effetto oltre a indicare una preferenza che le chiamate di quella funzione dovrebbero essere ottimizzate rispetto alle chiamate di altre funzioni dichiarate senza la inline
parola chiave.
La visibilità è un problema per una chiamata di una funzione con collegamento esterno in cui la chiamata si trova in un'unità di traduzione diversa dalla definizione della funzione. In questo caso, la inline
parola chiave consente all'unità di traduzione contenente la chiamata di contenere anche una definizione locale, o inline, della funzione.
Un programma può contenere un'unità di traduzione con una definizione esterna, un'unità di traduzione con una definizione inline e un'unità di traduzione con una dichiarazione ma nessuna definizione per una funzione. Le chiamate in quest'ultima unità di traduzione useranno la definizione esterna come al solito.
Una definizione inline di una funzione è considerata una definizione diversa dalla definizione esterna. Se si verifica una chiamata a una funzione func
con collegamento esterno dove è visibile una definizione inline, il comportamento è lo stesso come se la chiamata fosse stata effettuata a un'altra funzione, ad esempio
__func
con collegamento interno. Un programma conforme non deve dipendere dalla funzione chiamata. Questo è il modello in linea nello Standard.
Un programma conforme non deve fare affidamento sull'implementazione utilizzando la definizione inline, né può fare affidamento sull'implementazione utilizzando la definizione esterna. L'indirizzo di una funzione è sempre l'indirizzo corrispondente alla definizione esterna, ma quando questo indirizzo viene utilizzato per chiamare la funzione, potrebbe essere utilizzata la definizione inline. Pertanto, il seguente esempio potrebbe non funzionare come previsto.
inline const char *saddr(void)
{
static const char name[] = "saddr";
return name;
}
int compare_name(void)
{
return saddr() == saddr(); // unspecified behavior
}
Poiché l'implementazione potrebbe utilizzare la definizione inline per una delle chiamate a saddr
e utilizzare la definizione esterna per l'altra, non è garantito che l'operazione di uguaglianza restituisca 1 (true). Ciò mostra che gli oggetti statici definiti all'interno della definizione inline sono distinti dal loro oggetto corrispondente nella definizione esterna. Ciò ha motivato il vincolo anche contro la definizione di un non const
oggetto di questo tipo.
L'inlining è stato aggiunto allo standard in modo tale da poter essere implementato con la tecnologia linker esistente e un sottoinsieme di inlining C99 è compatibile con C ++. Ciò è stato ottenuto richiedendo che esattamente un'unità di traduzione contenente la definizione di una funzione inline sia specificata come quella che fornisce la definizione esterna per la funzione. Perché quella specifica consiste semplicemente di una dichiarazione che o manca la inline
parola chiave, o contiene sia inline
e extern
, sarà anche accettati da un traduttore C ++.
L'inlining in C99 estende la specifica C ++ in due modi. Primo, se una funzione è dichiarata
inline
in un'unità di traduzione, non è necessario che sia dichiarata inline
in ogni altra unità di traduzione. Ciò consente, ad esempio, una funzione di libreria che deve essere inline all'interno della libreria ma disponibile solo tramite una definizione esterna altrove. L'alternativa di utilizzare una funzione wrapper per la funzione esterna richiede un nome aggiuntivo; e può anche avere un impatto negativo sulle prestazioni se un traduttore non esegue effettivamente la sostituzione in linea.
In secondo luogo, il requisito che tutte le definizioni di una funzione inline siano "esattamente le stesse" è sostituito dal requisito che il comportamento del programma non debba dipendere dal fatto che una chiamata sia implementata con una definizione inline visibile, o la definizione esterna, di un funzione. Ciò consente a una definizione inline di essere specializzata per il suo utilizzo all'interno di una particolare unità di traduzione. Ad esempio, la definizione esterna di una funzione di libreria potrebbe includere una convalida di argomenti che non è necessaria per le chiamate effettuate da altre funzioni nella stessa libreria. Queste estensioni offrono alcuni vantaggi; ei programmatori preoccupati per la compatibilità possono semplicemente attenersi alle regole C ++ più rigide.
Si noti che è non è appropriato per le implementazioni di fornire definizioni in linea di funzioni della libreria standard nelle intestazioni standard, perché questo può rompere alcune codice legacy che redeclares funzioni della libreria standard dopo compresi i loro intestazioni. La inline
parola chiave ha il solo scopo di fornire agli utenti un modo portabile per suggerire l'integrazione di funzioni. Poiché le intestazioni standard non devono essere portabili, le implementazioni hanno altre opzioni sulla falsariga di:
#define abs(x) __builtin_abs(x)
o altri meccanismi non portabili per incorporare funzioni di libreria standard.