2010-03-06 6 views

risposta

11

Ricordare che includere qualcosa da un'intestazione non è diverso dal solo digitarlo direttamente nel file sorgente. Quindi essere in un header non fa differenza per quanto riguarda il compilatore; non ha mai saputo che era lì.

Così quando si definisce una funzione in un file di intestazione e si include quel file di intestazione in un file, è come se si fosse appena inserita la funzione direttamente nel file. Quindi ora la domanda è: "il compilatore sceglie di integrare le cose in base all'euristica?"

La risposta è "dipende dal compilatore". Lo standard non fornisce garanzie su ciò che viene sottolineato o meno. Detto questo, qualsiasi compilatore moderno sarà estremamente intelligente su ciò che è in linea, probabilmente con euristica.

Tuttavia, arriviamo a un punto interessante. Immagina di avere una funzione in un'intestazione e di includere quell'intestazione in più file sorgente. Avrai quindi più definizioni della funzione, attraverso le unità di traduzione, e questo viola la regola a una definizione. Ergo, riceverai errori di compilazione. (L'errore del linker è di solito qualcosa del tipo: "Errore, funzione x già definito in y"). Ciò che puoi fare è usare la parola chiave inline e non devi più violare l'ODR.

A proposito, __inline non standard. Contrariamente al tuo post, di solito è un'estensione del compilatore che forza l'inlining, non lo suggerisce. inline è la parola chiave standard, che originariamente era intesa come suggerimento di inlining. Come dici tu, la maggior parte dei compilatori moderni la ignorano completamente al riguardo e il suo unico scopo oggi è dare un collegamento interno alle cose.

+0

Qualche idea su quale euristica un moderno compilatore come g ++ usa nella sua decisione? cioè è sulla falsariga di "inline qualsiasi funzione che in cui il rapporto tra siti di chiamata e byte in funzione è inferiore a X"? O è qualcosa di più sottile? –

+0

@Jeremy: Non ne ho idea, anche se sono molto interessato ora che mi parli. Potrò guardare stasera. Sospetto che sia piuttosto complicato. – GManNickG

+1

@GMan: il bit relativo al collegamento interno non è corretto. 'inline' non ha effetto sul collegamento. In C++ una funzione dichiarata 'inline' ha un collegamento esterno (a meno che non sia specificatamente dichiarato' static'), proprio come qualsiasi altra funzione. L'ODR per le funzioni in linea consente specificamente più definizioni in diverse unità di traduzione, anche se il collegamento è esterno. – AnT

2

Verrà scelto in base all'euristica. Assicurati di dichiararlo esplicitamente in linea altrimenti potresti ottenere un errore di collegamento simbolico duplicato se includi l'intestazione in più di una unità di compilazione.

4

Dal C++ FAQ Lite:

Non importa come si designa una funzione come inline, è una richiesta che il compilatore è consentito di ignorare: è potrebbe inline-espandere alcuni, tutti o nessuno delle chiamate a una funzione in linea.

2

Se definisce una funzione con collegamento esterno in un file di intestazione e includerlo in più di un'unità di traduzione, si otterrà errore di compilazione (più precisamente: linker erorr) per violazione di una regola Definizione (ODR). Quindi la risposta è "no": la definizione di una funzione in un file di intestazione non verrà presa dal compilatore come suggerimento di inlining e non ti scuserà dall'osservare i requisiti dell'ODR. Non solo le funzioni non sono garantite per essere sottolineate, ma molto probabilmente il tuo programma non verrà nemmeno compilato.

Per definire una funzione in un file di intestazione e farla franca bisogna assegnargli un collegamento interno (dichiararlo static, e finire con una funzione separata in ogni unità di traduzione), o dichiararlo esplicitamente inline.

Per quanto riguarda l'euristica ...I compilatori moderni considereranno normalmente praticamente qualsiasi funzione di inlining (applicando l'euristica), indipendentemente da dove è definita e se è esplicitamente dichiarata inline oppure no.

1

Non c'è magia sulle funzioni nelle intestazioni. Il compilatore non sa nemmeno se una funzione è definita in un'intestazione o meno. (Dal momento che le intestazioni sono effettivamente copiate/incollate nel file sorgente, è possibile definirla in un'intestazione, ma il compilatore la vede semplicemente come parte dell'unità di traduzione)

Ci sono anche due diversi significati di "in linea" per essere a conoscenza:

una funzione può essere inlined come definito dallo standard C++: Ciò avviene anteponendo la funzione della parola inline, o se non é una funzione membro, definendo in posto all'interno definizione della classe.

L'effetto di questo è di

  • informare il linker che possa incontrare la definizione di funzione in più file, e dovrebbe semplicemente in silenzio fonderli insieme invece di generare un errore
  • agevolare l'accesso il compilatore per eseguire l'ottimizzazione integrata.

L'inlining ottimizzazione invece, è semplicemente l'atto di sostituzione di una chiamata di funzione dal corpo della funzione chiamata, il che significa che questa ottimizzazione è effettivamente applicata a chiamare altri siti, non funzioni. Una funzione potrebbe essere chiamata normalmente in alcuni posti, ma in linea altrove. Una chiamata di funzione è inline quando il compilatore si sente come tale, ed è meglio separarla concettualmente dal primo significato di "inline".

Il compilatore applicherà l'ottimizzazione inlining se, quando e dove ci si sente. Usa molte euristiche per questo. È più probabile che le funzioni più piccole siano in linea. Se determina che uno specifico sito di chiamata verrà eseguito abbastanza spesso, è più probabile che sia in linea. In definitiva, l'euristica utilizzata è basata su "migliorerà o degraderà le prestazioni". Ed è generalmente un giudice migliore di questo rispetto agli esseri umani, quindi non dovresti davvero sapere quale euristica precisa usa. Inlining troppo danneggerà solo le prestazioni.