extern inline

Je comprends que “inline” en soi est une suggestion pour le compilateur, et à sa discrétion, il peut ou non incorporer la fonction, et il produira également du code object pouvant être lié.

Je pense que “static inline” fait la même chose (peut-être ou non), mais ne produira pas de code object pouvant être lié lorsqu’il est inséré (aucun autre module ne pouvant y être lié).

Où “extern inline” s’intègre-t-il dans l’image?

Supposons que je veuille remplacer une macro de préprocesseur par une fonction inline et que cette fonction soit intégrée (par exemple, parce qu’elle utilise les macros __FILE__ et __LINE__ qui doivent être résolues pour l’appelant mais pas pour cette fonction appelée). C’est-à-dire que je veux voir une erreur du compilateur ou de l’éditeur de liens au cas où la fonction ne serait pas mise en ligne. Est-ce que “extern inline” fait cela? (Je suppose que si ce n’est pas le cas, il n’y a aucun moyen de réaliser ce comportement autre que de s’en tenir à une macro.)

Y a-t-il des différences entre C ++ et C?

Existe-t-il des différences entre les différents fournisseurs et versions du compilateur?

dans K & R C ou C89, inline ne faisait pas partie de la langue. De nombreux compilateurs l’ont implémenté en tant qu’extension, mais aucune sémantique n’était définie quant à son fonctionnement. GCC a été parmi les premiers à implémenter l’inline, et a introduit les constructions inline , static inline et extern inline ; la plupart des compilateurs pré-C99 suivent généralement son exemple.

GNU89:

  • inline : la fonction peut être intégrée (c’est juste un indice). Une version hors ligne est toujours émise et visible de l’extérieur. Vous ne pouvez donc avoir qu’une telle ligne définie dans une unité de compilation, et tous les autres doivent la voir comme une fonction hors ligne (ou vous obtiendrez des symboles en double au moment de la liaison).
  • extern inline ne générera pas de version hors ligne, mais pourrait en appeler une (que vous devez donc définir dans une autre unité de compilation. La règle à une définition s’applique, cependant, la version hors ligne doit avoir le même code). comme l’inline offert ici, au cas où le compilateur l’appelle à la place.
  • static inline ne générera pas de version hors ligne visible en externe, bien qu’il puisse générer un fichier statique. La règle à une définition ne s’applique pas, car il n’y a jamais de symbole externe émis ni d’appel à un.

C99 (ou GNU99):

  • inline : comme GNU89 “extern inline”; aucune fonction visible de l’extérieur n’est émise, mais une peut être appelée et doit exister
  • extern inline : comme GNU89 “inline”: du code visible de l’extérieur est émis, donc au plus une unité de traduction peut l’utiliser.
  • static inline : comme GNU89 “statique en ligne”. C’est le seul portable entre gnu89 et c99

C ++:

Une fonction qui est en ligne n’importe où doit être en ligne partout, avec la même définition. Le compilateur / éditeur de liens sortingera plusieurs instances du symbole. Il n’y a pas de définition de static inline ou extern inline , bien que de nombreux compilateurs en disposent (généralement selon le modèle gnu89).

Je crois que vous avez mal compris __FILE__ et __LINE__ sur la base de cette déclaration:

car il utilise les macros __FILE__ et __LINE__ qui devraient résoudre pour l’appelant mais pas cette fonction appelée

Il existe plusieurs phases de compilation et le prétraitement est le premier. __FILE__ et __LINE__ sont remplacés pendant cette phase. Donc, au moment où le compilateur peut considérer la fonction d’inline, ils ont déjà été remplacés.

On dirait que vous essayez d’écrire quelque chose comme ceci:

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

et en espérant que vous aurez des valeurs différentes imprimées à chaque fois. Comme Don le dit, vous ne le ferez pas, car __FILE__ et __LINE__ sont implémentés par le préprocesseur, mais en ligne sont implémentés par le compilateur. Donc, où que vous appeliez printLocation, vous obtiendrez le même résultat.

La seule façon de faire fonctionner ceci est de faire de printLocation une macro. (Oui je sais...)

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

La situation avec inline, static inline et extern inline est compliquée, notamment parce que gcc et C99 définissent des significations légèrement différentes pour leur comportement (et probablement aussi pour C ++). Vous pouvez trouver des informations utiles et détaillées sur ce qu’ils font en C ici .

Les macros sont votre choix ici plutôt que les fonctions en ligne. Une rare occasion où les macros gèrent les fonctions en ligne. Essayez ce qui suit: J’ai écrit ce code “MACRO MAGIC” et ça devrait marcher! Testé sur 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; } 

Pour plusieurs fichiers, définissez ces macros dans un fichier d’en-tête distinct, y compris les mêmes dans chaque fichier c / cc / cxx / cpp. Préférez les fonctions en ligne ou les identifiants const (comme le demande le cas) sur les macros dans la mesure du possible.

Au lieu de répondre “qu’est-ce que ça fait?”, Je réponds “comment je le fais faire ce que je veux?” Il existe 5 types d’inlining, tous disponibles dans GNU C89, standard C99 et C ++:

toujours en ligne, sauf si l’adresse est prise

Ajoutez __atsortingbute__((always_inline)) à toute déclaration, puis utilisez l’un des cas ci-dessous pour gérer la possibilité que son adresse soit prise.

Vous ne devriez probablement jamais utiliser ceci, à moins que vous n’ayez besoin de sa sémantique (par exemple pour affecter l’assemblage d’une certaine manière ou pour utiliser alloca ). Le compilateur sait généralement mieux que vous si cela en vaut la peine.

en ligne et émettre un symbole faible (comme C ++, alias “juste le faire fonctionner”)

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

Notez que cela laisse un tas de copies du même code qui traînent, et l’éditeur de liens en choisit une arbitrairement.

inline, mais n’émet jamais de symbole (laissant des références externes)

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

émettre toujours (pour une TU, pour résoudre le précédent)

La version suggérée émet un symbole faible en C ++, mais un symbole fort dans les deux dialectes de C:

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

Ou vous pouvez le faire sans le conseil, qui émet un symbole fort dans les deux langues:

 void foo(void) { ... } 

Généralement, vous savez quelle langue est votre TU lorsque vous fournissez les définitions et que vous n’avez probablement pas besoin

en ligne et émettre dans chaque UE

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

À l’exception de la version static , vous pouvez append une déclaration void foo(void) ci-dessus. Cela aide à “mieux” écrire des en-têtes propres, puis à #include un fichier séparé avec les définitions en ligne. Ensuite, si vous utilisez des lignes de style C, #define définissez une macro différemment dans une UT dédiée pour fournir les définitions hors ligne.

N’oubliez pas extern "C" si l’en-tête peut être utilisé à la fois en C et C ++!