102 votes

Que fait extern inline ?

Je comprends que inline par lui-même est une suggestion au compilateur, et à sa discrétion, il peut ou non mettre la fonction en ligne, et il produira également du code objet lisible.

Je pense que static inline fait la même chose (peut être ou ne pas être inline) mais ne produira pas de code objet lisible lorsqu'il est inline (puisqu'aucun autre module ne peut le lier).

Où se trouve extern inline s'intégrer dans le tableau ?

Supposons que je veuille remplacer une macro du préprocesseur par une fonction inline et que je souhaite que cette fonction soit inline (par exemple, parce qu'elle utilise la fonction __FILE__ y __LINE__ qui doivent être résolues pour l'appelant mais pas pour la fonction appelée). En d'autres termes, je veux voir une erreur du compilateur ou de l'éditeur de liens au cas où la fonction ne serait pas inlined. Est-ce que extern inline faire ça ? (Je suppose que, si ce n'est pas le cas, il n'y a pas d'autre moyen d'obtenir ce comportement 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 de compilateurs ?

140voto

puetzk Points 5099

Dans K&R C ou C89, l'inline ne faisait pas partie du langage. De nombreux compilateurs l'implémentaient comme une extension, mais il n'y avait pas de sémantique définie concernant son fonctionnement. GCC a été parmi les premiers à implémenter l'inlining, et a introduit la fonction inline , static inline et extern inline La plupart des compilateurs pré-C99 suivent généralement son exemple.

GNU89 :

  • inline la fonction peut être inlined (c'est juste une indication). Une version hors ligne est toujours émise et visible de l'extérieur. Par conséquent, vous ne pouvez avoir une telle fonction inline définie que dans une seule unité de compilation, et toutes les autres unités doivent la voir comme une fonction out-of-line (ou vous obtiendrez des symboles en double au moment de la liaison).
  • extern inline ne génère pas de version hors ligne, mais peut en appeler une (que vous devez donc définir dans une autre unité de compilation). La règle de la définition unique s'applique cependant ; la version hors ligne doit avoir le même code que la version en ligne proposée ici, au cas où le compilateur l'appellerait à la place.
  • static inline ne génère pas de version hors ligne visible de l'extérieur, mais elle peut générer une version statique dans le fichier. La règle de la définition unique ne s'applique pas, puisqu'il n'y a jamais de symbole externe émis ni d'appel à un symbole.

C99 (ou GNU99) :

  • inline : comme GNU89 "extern inline" ; aucune fonction visible de l'extérieur n'est émise, mais une fonction peut être appelée et doit donc exister.
  • extern inline : comme GNU89 "inline" : le code visible de l'extérieur est émis, donc au maximum une unité de traduction peut l'utiliser.
  • static inline : comme GNU89 "static inline". C'est la seule portable entre gnu89 et c99.

C++ :

Une fonction qui est en ligne partout doit être en ligne partout, avec la même définition. Le compilateur/lien triera les instances multiples 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 de gnu89).

32voto

Don Neufeld Points 12803

Je crois que vous comprenez mal __FILE__ et __LINE__ d'après cette déclaration :

parce qu'il utilise le __FILE__ et le __FILE__. __LINE__ qui devraient être résolues pour l'appelant, mais pas pour cet appelé. fonction

Il y a plusieurs phases de compilation, et le prétraitement est la première. Les __FILE__ et __LINE__ sont remplacés pendant cette phase. Ainsi, au moment où le compilateur peut considérer la fonction pour l'inlining, elles ont déjà été remplacées.

14voto

Roddy Points 32503

On dirait que vous essayez d'écrire quelque chose comme ça :

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

{
...
  printLocation();
...
  printLocation();
...
  printLocation();

et en espérant que vous obtiendrez des valeurs différentes à chaque fois. Comme le dit Don, ce n'est pas le cas, car __FILE__ et __LINE__ sont implémentés par le préprocesseur, mais inline est implémenté par le compilateur. Ainsi, quel que soit l'endroit où vous appelez printLocation, vous obtiendrez le même résultat.

En seulement Pour que cela fonctionne, il faut faire de printLocation une macro. (Oui, je sais...)

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

...
  PRINT_LOCATION;
...
  PRINT_LOCATION;
...

4voto

o11c Points 1687

Au lieu de répondre "qu'est-ce que ça fait ?", je réponds "comment faire pour que ça fasse ce que je veux ?". Il y a 5 types d'inlining, tous disponibles dans GNU C89, C99 standard, et C++. MSVC a un peu de d'entre eux (notez que je n'ai pas testé le code MSVC)

toujours en ligne, sauf si l'adresse est prise

Ajouter __attribute__((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 l'utiliser, sauf si vous avez 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.

MSVC a __forceinline qui semble être le même, mais apparemment, il refuse de s'aligner dans un certain nombre de circonstances courantes (par exemple, lorsque l'optimisation est désactivée) alors que d'autres compilateurs s'en sortent très bien.

inline et émettre un symbole faible (comme en C++, c'est-à-dire "faites que ça marche")

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

Notez que cela laisse un tas de copies du même code, et le linker en choisit une arbitrairement.

MSVC ne semble pas avoir d'équivalent exact en mode C, bien qu'il y ait un certain nombre de choses similaires. __declspec(selectany) semble ne parler que des données, et ne s'applique donc peut-être pas aux fonctions ? Il existe également un support de linker pour alias faibles mais est-ce que ça marche ici ?

en ligne, mais n'émettent jamais de symbole (laissant des références externes)

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

MSVC's __declspec(dllimport) combiné à une définition réelle (par ailleurs inhabituelle), est censé faire cela.

émettre toujours (pour un TU, pour résoudre ce qui précède)

La version hinted émet un symbole faible en C++, mais un symbole fort dans l'un ou l'autre dialecte du C :

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

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

void foo(void) { ... }

En général, vous savez quel est le langage de votre UT lorsque vous fournissez les définitions, et vous n'avez probablement pas besoin de beaucoup d'inlining.

MSVC's __declspec(dllexport) est censé le faire.

en ligne et émettent dans chaque TU

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

Pour tous ces éléments, sauf le static un, vous pouvez ajouter un void foo(void) déclaration ci-dessus. Cela permet de respecter la "meilleure pratique" consistant à écrire des en-têtes propres, alors #include dans un fichier séparé avec les définitions en ligne. Ensuite, si vous utilisez des inlines de style C, #define une macro différente dans une TU 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 en C++ !


Il y a aussi quelques éléments connexes :

jamais en ligne

Ajouter __attribute__((noinline)) à toute déclaration de la fonction.

MSVC a __declspec(noinline) mais il est documenté pour ne fonctionner que pour les fonctions membres. Cependant, j'ai vu la mention d'"attributs de sécurité" qui pourraient empêcher l'inlining ?

obliger les autres fonctions à être intégrées dans celle-ci si possible.

Ajouter __attribute__((flatten)) à toute déclaration de la fonction.

Notez que noinline est plus puissant que cela, tout comme les fonctions dont la définition n'est pas connue au moment de la compilation.

MSVC ne semble pas avoir d'équivalent. J'ai vu une seule mention de [[msvc::forceinline_calls]] (appliqué à une déclaration ou un bloc), mais il n'est pas récursif.

3voto

Simon Howard Points 5392

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 vraisemblablement C++ aussi). Vous pouvez trouver des informations utiles et détaillées sur ce qu'ils font en C ici .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X