esternamente in linea

Capisco che “in linea” sia di per sé un suggerimento per il compilatore, e alla sua descrizione potrebbe o meno in-lineare la funzione, e produrrà anche codice object collegabile.

Penso che “static inline” faccia lo stesso (potrebbe o non sia in linea) ma non produrrà codice object collegabile quando è in linea (poiché nessun altro modulo potrebbe collegarsi ad esso).

Dove si inserisce “esternamente in linea” nell’immagine?

Supponiamo di voler sostituire una macro del preprocessore con una funzione inline e richiedere che questa funzione venga allineata (ad esempio, poiché utilizza i macro __FILE__ e __LINE__ che dovrebbero risolversi per il chiamante ma non questa funzione chiamata). Cioè, voglio vedere un errore del compilatore o del linker nel caso in cui la funzione non venga evidenziata. “Extern inline” fa questo? (Suppongo che, in caso contrario, non ci sia modo di ottenere questo comportamento se non attenersi a una macro.)

Ci sono differenze tra C ++ e C?

Ci sono differenze tra diversi produttori di compilatori e versioni?

in K & R C o C89, inline non faceva parte della lingua. Molti compilatori l’hanno implementato come un’estensione, ma non c’erano semantiche definite su come funzionava. GCC è stato tra i primi a implementare l’inlining e ha introdotto i costrutti extern inline , static inline e extern inline ; la maggior parte del compilatore pre-C99 segue generalmente il suo esempio.

gnu89:

  • inline : la funzione può essere in linea (è solo un suggerimento). Una versione fuori linea viene sempre emessa ed esternamente visibile. Quindi puoi avere solo un inline definito in una unità di compilazione, e ogni altro deve vederlo come una funzione fuori linea (o otterrai simboli duplicati al momento del collegamento).
  • extern inline non genererà una versione fuori linea, ma potrebbe chiamarne una (che quindi devi definire in qualche altra unità di compilazione.) La regola a una definizione si applica, tuttavia la versione fuori linea deve avere lo stesso codice come inline offerto qui, nel caso in cui il compilatore lo chiami.
  • static inline non genererà una versione out-of-line visibile esternamente, sebbene possa generare un file statico. La regola a una definizione non si applica, poiché non c’è mai un simbolo esterno emesso né una chiamata a uno.

C99 (o GNU99):

  • inline : come GNU89 “extern inline”; non viene emessa alcuna funzione visibile esternamente, ma si potrebbe chiamare uno e quindi deve esistere
  • extern inline : come GNU89 “inline”: il codice esternamente visibile viene emesso, quindi al massimo una unità di traduzione può usarlo.
  • static inline : come GNU89 “statico in linea”. Questo è l’unico portatile tra gnu89 e c99

C ++:

Una funzione che è in linea ovunque deve essere in linea ovunque, con la stessa definizione. Il compilatore / linker risolve più istanze del simbolo. Non esiste una definizione di static inline o extern inline , sebbene molti compilatori li abbiano (in genere seguendo il modello gnu89).

Credo che tu abbia frainteso __FILE__ e __LINE__ basandosi su questa affermazione:

perché usa le macro __FILE__ e __LINE__ che dovrebbero risolversi per il chiamante ma non questa funzione chiamata

Ci sono diverse fasi di compilazione e la pre-elaborazione è la prima. __FILE__ e __LINE__ vengono sostituiti durante questa fase. Quindi, quando il compilatore può prendere in considerazione la funzione di inlining, è già stato sostituito.

Sembra che tu stia cercando di scrivere qualcosa del genere:

 inline void printLocation() { cout <<"You're at " __FILE__ ", line number" __LINE__; } { ... printLocation(); ... printLocation(); ... printLocation(); 

e sperando che otterrai sempre valori diversi stampati. Come dice Don, non lo farai, perché __FILE__ e __LINE__ sono implementati dal preprocessore, ma inline è implementato dal compilatore. Quindi, ovunque tu chiami printLocation, otterrai lo stesso risultato.

L' unico modo per farlo funzionare è rendere una macro una destinazione di stampa. (Si, lo so...)

 #define PRINT_LOCATION {cout <<"You're at " __FILE__ ", line number" __LINE__} ... PRINT_LOCATION; ... PRINT_LOCATION; ... 

La situazione con inline, linea statica interna ed esterna è complicata, non ultimo perché gcc e C99 definiscono significati leggermente diversi per il loro comportamento (e presumibilmente anche per C ++). Puoi trovare alcune informazioni utili e dettagliate su ciò che fanno in C qui .

Le macro sono la tua scelta qui piuttosto che le funzioni inline. Una rara occasione in cui i macro governano su funzioni inline. Prova quanto segue: Ho scritto questo codice “MACRO MAGIC” e dovrebbe funzionare! Testato su gcc / g ++ Ubuntu 10.04

 //(c) 2012 enthusiasticgeek (LOGGING example for StackOverflow) #ifdef __cplusplus #include  #include  #else #include  #include  #endif //=========== MACRO MAGIC BEGINS ============ //Trim full file path #define __SFILE__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/')+1 : __FILE__ ) #define STRINGIFY_N(x) #x #define TOSTRING_N(x) STRINGIFY_N(x) #define _LINE (TOSTRING_N(__LINE__)) #define LOG(x, s...) printf("(%s:%s:%s)" x "\n" , __SFILE__, __func__, _LINE, ## s); //=========== MACRO MAGIC ENDS ============ int main (int argc, char** argv) { LOG("Greetings StackOverflow! - from enthusiasticgeek\n"); return 0; } 

Per file multipli, definire queste macro in un file di intestazione separato, incluso lo stesso in ogni file c / cc / cxx / cpp. Si prega di preferire le funzioni in linea o gli identificatori const (come richiesto dal caso) su macro, ove ansible.

Invece di rispondere “cosa fa?”, Sto rispondendo “come faccio a fare ciò che voglio?” Esistono 5 tipi di inlining, tutti disponibili in GNU C89, standard C99 e C ++:

sempre in linea, a meno che non venga preso l’indirizzo

Aggiungi __attribute__((always_inline)) a qualsiasi dichiarazione, quindi utilizza uno dei seguenti casi per gestire la possibilità che il suo indirizzo venga preso.

Probabilmente non dovresti mai usarlo, a meno che tu non abbia bisogno della sua semantica (ad esempio per influenzare l’assemblaggio in un certo modo, o per usare alloca ). Il compilatore di solito sa meglio di te se ne vale la pena.

in linea ed emette un simbolo debole (come C ++, ovvero “fallo funzionare”)

 __attribute__((weak)) void foo(void); inline void foo(void) { ... } 

Si noti che questo lascia un mucchio di copie dello stesso codice in giro, e il linker ne sceglie uno arbitrariamente.

in linea, ma non emette mai alcun simbolo (lasciando riferimenti esterni)

 __attribute__((gnu_inline)) extern inline void foo(void) { ... } 

emetti sempre (per una TU, per risolvere il precedente)

La versione suggerita emette un simbolo debole in C ++, ma un simbolo forte in entrambi i dialetti di C:

 void foo(void); inline void foo(void) { ... } 

Oppure puoi farlo senza il suggerimento, che emette un forte simbolo in entrambe le lingue:

 void foo(void) { ... } 

In genere, sai qual è la lingua della tua TU quando stai fornendo le definizioni e probabilmente non hai bisogno di molte spiegazioni.

inline ed emetti in ogni TU

 static inline void foo(void) { ... } 

Per tutti questi eccetto quello static , è ansible aggiungere una dichiarazione void foo(void) sopra. Questo aiuta con la “migliore pratica” di scrivere intestazioni pulite, quindi #include un file separato con le definizioni incorporate. Quindi, se si utilizzano inline stile C, #define alcune macro in modo diverso in una TU dedicata per fornire le definizioni out-of-line.

Non dimenticare extern "C" se l’intestazione potrebbe essere utilizzata sia da C che da C ++!