Qual è la differenza tra la funzione "statica" e "statica in linea"?


123

IMO entrambi fanno in modo che la funzione abbia solo un ambito dell'unità di traduzione.

Qual è la differenza tra la funzione "statica" e "statica in linea"?

Perché dovrebbe inlineessere messo in un file di intestazione, non in un .cfile?

Risposte:


109

inlineindica al compilatore di tentare di incorporare il contenuto della funzione nel codice chiamante invece di eseguire una chiamata effettiva.

Per piccole funzioni chiamate frequentemente che possono fare una grande differenza di prestazioni.

Tuttavia, questo è solo un "suggerimento" e il compilatore potrebbe ignorarlo e la maggior parte dei compilatori tenterà di "inline" anche quando la parola chiave non viene utilizzata, come parte delle ottimizzazioni, ove possibile.

per esempio:

static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};

Questo ciclo stretto eseguirà una chiamata di funzione a ogni iterazione e il contenuto della funzione è in realtà notevolmente inferiore al codice che il compilatore deve inserire per eseguire la chiamata. inlineessenzialmente istruirà il compilatore a convertire il codice sopra in un equivalente di:

 int i;
 ....
 for (i=0; i<999999; i = i+1) { /* do something here */};

Saltare la chiamata alla funzione effettiva e tornare indietro

Ovviamente questo è un esempio per mostrare il punto, non un vero pezzo di codice.

staticsi riferisce all'ambito. In C significa che la funzione / variabile può essere utilizzata solo all'interno della stessa unità di traduzione.


4
No, si staticriferisce all'ambito. In C significa che la funzione / variabile può essere utilizzata solo all'interno della stessa unità di traduzione.
littleadv

8
È anche importante notare che il codice dichiarato come inline appartiene all'intestazione, dove come normale codice sorgente (non modello) non può essere inserito nelle intestazioni senza causare più errori di ridefinizione. Quindi anche quando si dichiara qualcosa inline, anche se il compilatore sceglie di non inline, c'è ancora una ridefinizione multipla standard che evita il comportamento che entra in gioco.
VoidStar

13
@VoidStar In realtà static(con o senza inline) può essere perfettamente nell'intestazione, non vedo motivo per cui no. I modelli sono per C ++, questa domanda riguarda C.
littleadv

2
@littleadv: il motivo principale per inserire le definizioni delle funzioni nei file di intestazione è renderli inlinabili, quindi contrassegnarli esplicitamente inlineè un buon stile, imo
Christoph

9
In realtà inlinenon indica al compilatore di eseguire alcun tentativo di inlining. Consente semplicemente al programmatore di includere il corpo della funzione in più unità di traduzione senza violazione ODR. Un effetto collaterale di ciò è che rende possibile al compilatore, quando vorrebbe inline la funzione, di farlo effettivamente.
Ruslan

96

Per impostazione predefinita, una definizione inline è valida solo nell'unità di traduzione corrente.

Se la classe di archiviazione è extern, l'identificatore ha un collegamento esterno e la definizione inline fornisce anche la definizione esterna.

Se la classe di archiviazione è static, l'identificatore ha un collegamento interno e la definizione inline è invisibile in altre unità di traduzione.

Se la classe di archiviazione non è specificata, la definizione inline è visibile solo nell'unità di traduzione corrente, ma l'identificatore ha ancora un collegamento esterno e deve essere fornita una definizione esterna in un'unità di traduzione diversa. Il compilatore è libero di utilizzare la definizione inline o esterna se la funzione viene chiamata all'interno dell'unità di traduzione corrente.

Poiché il compilatore è libero di incorporare (e non inline) qualsiasi funzione la cui definizione è visibile nell'unità di traduzione corrente (e, grazie alle ottimizzazioni del tempo di collegamento, anche in unità di traduzione diverse, sebbene lo standard C non tenga realmente conto che), per la maggior parte degli scopi pratici, non c'è differenza tra le definizioni di funzione statice static inline.

Lo inlinespecificatore (come la registerclasse di archiviazione) è solo un suggerimento per il compilatore e il compilatore è libero di ignorarlo completamente. I compilatori non ottimizzanti conformi agli standard devono solo onorare i loro effetti collaterali, e i compilatori ottimizzati eseguiranno queste ottimizzazioni con o senza suggerimenti espliciti.

inlinee registernon sono inutili, tuttavia, poiché istruiscono il compilatore a generare errori quando il programmatore scrive codice che renderebbe impossibili le ottimizzazioni: una inlinedefinizione esterna non può fare riferimento a identificatori con collegamento interno (poiché questi non sarebbero disponibili in un'unità di traduzione diversa) oppure definire variabili locali modificabili con durata di memorizzazione statica (poiché queste non condividono lo stato tra le unità di traduzione) e non è possibile prendere indirizzi di registervariabili -qualificate.

Personalmente, utilizzo la convenzione per contrassegnare le staticdefinizioni di funzione anche all'interno delle intestazioni inline, poiché il motivo principale per inserire le definizioni di funzione nei file di intestazione è renderle inlinabili.

In generale, uso solo definizioni di static inlinefunzioni e static constoggetti oltre alle externdichiarazioni all'interno delle intestazioni.

Non ho mai scritto una inlinefunzione con una classe di archiviazione diversa da static.


8
Questa è la risposta corretta. Qualsiasi risposta che parli inlinecome se fosse effettivamente applicata all'inlining è fuorviante e probabilmente non corretta. Nessun compilatore moderno lo usa come suggerimento per inline o richiederlo per abilitare l'inlining di una funzione.
Tyg13

1
upvoted per "usa la convenzione per contrassegnare le definizioni di funzioni statiche nelle intestazioni inline".
John Z. Li

Ho letto la tua intera risposta e ancora non ho capito la differenza semantica tra statice static inline. Entrambi rendono la definizione invisibile alle altre unità di traduzione. Quindi quale sarebbe una ragione ragionevole per scrivere static inlineinvece di static?
user541686

21

Dalla mia esperienza con GCC lo so statice static inlinedifferisce in un modo in cui il compilatore emette avvisi sulle funzioni inutilizzate. Più precisamente quando dichiari la staticfunzione e non è utilizzata nell'unità di traduzione corrente, il compilatore produce un avviso sulla funzione inutilizzata, ma puoi inibire quell'avvertimento cambiandolo in static inline.

Quindi tendo a pensare che staticdovrebbe essere usato nelle unità di traduzione e trarre vantaggio dal controllo extra del compilatore per trovare le funzioni inutilizzate. E static inlinedovrebbe essere utilizzato nei file di intestazione per fornire funzioni che possono essere allineate (a causa dell'assenza di collegamenti esterni) senza emettere avvisi.

Purtroppo non riesco a trovare alcuna prova per questa logica. Anche dalla documentazione di GCC non sono riuscito a concludere che inlineinibisca gli avvisi di funzione inutilizzati. Apprezzerei se qualcuno condividesse i link alla descrizione di questo.


1
Mmm, ho ancora warning: unused function 'function' [clang-diagnostic-unused-function]una static inlinefunzione durante la clang-tidycompilazione con (v8.0.1), che viene utilizzata in un'altra unità di traduzione. Ma sicuramente, questa è una delle migliori spiegazioni e ragioni per combinare static& inline!
DrumM

6

In C, staticsignifica che la funzione o la variabile che definisci può essere usata solo in questo file (cioè l'unità di compilazione)

Quindi, static inlineindica la funzione inline che può essere utilizzata solo in questo file.

MODIFICARE:

L'unità di compilazione dovrebbe essere The Translation Unit


2
O in parole fantasiose: ha un collegamento interno.
K-ballo

@AlokSave: c'è una differenza tra l' unità di compilazione e l' unità di traduzione ? In caso affermativo, quale è più appropriato nel contesto del linguaggio C ++?
legends2k

Credo the compile unitsia qualcosa che ho scritto per errore, non esiste una cosa del genere, la terminologia effettiva ètranslation unit
shengy

La tua risposta non è completa perché viene utilizzata principalmente nei file di intestazione, in tutte le unità di traduzione.
DrumM

5

Una differenza non è a livello di linguaggio, ma a livello di implementazione popolare: alcune versioni di gcc rimuoveranno le static inlinefunzioni non referenziate dall'output per impostazione predefinita, ma manterranno le staticfunzioni semplici anche se non referenziate. Non sono sicuro a quali versioni si applichi, ma da un punto di vista pratico significa che potrebbe essere una buona idea usare sempre inlineper le staticfunzioni nelle intestazioni.


Che dire dell'uso inlinenella definizione? Implica anche di non usarlo per le externfunzioni?
new_perl

È ancora vero con la versione recente di GCC? La tua risposta sarebbe molto più interessante se fornissi un esempio e elencassi quale versione di GCC lo fa.
Bosone Z

@Zboson: Non ho queste informazioni prontamente disponibili e non ho tempo per configurare e testare molte versioni di gcc al momento, ma sono d'accordo che sarebbe utile avere informazioni. Probabilmente potresti scoprire quando gcc ha iniziato a ottimizzare funzioni / oggetti statici inutilizzati osservando la cronologia attribute((used))e il suo utilizzo per consentire ad asm di fare riferimento a staticfunzioni e dati altrimenti non referenziati .
R .. GitHub SMETTA DI AIUTARE IL GHIACCIO
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.