web-dev-qa-db-fra.com

extern inline

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

Je pense que "statique en ligne" fait la même chose (peut ou peut ne pas être en ligne) mais ne produira pas de code objet pouvant être lié lorsqu'il est en ligne (car aucun autre module ne pourrait y être lié).

Où se situe "extern inline" dans la photo?

Supposons que je souhaite remplacer une macro de préprocesseur par une fonction en ligne et que cette fonction soit intégrée (par exemple, car elle utilise les macros __FILE__ et __LINE__ qui doivent être résolues pour l'appelant, mais pas pour la fonction appelée). C'est-à-dire que je souhaite voir une erreur du compilateur ou de l'éditeur de liens au cas où la fonction ne serait pas en ligne. Est-ce que "extern inline" fait ça? (Je suppose que si ce n’est pas le cas, il n’ya aucun autre moyen d’obtenir ce comportement autre que de rester avec une macro.)

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

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

83
wilbur_m

dans K & R C ou C89, inline ne faisait pas partie du langage. De nombreux compilateurs l'ont implémentée 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'inline et a introduit les constructions inline, static inline et extern inline; la plupart des compilateurs pré-C99 suivent généralement son avance. 

GNU89:

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

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 donc exister
  • extern inline: comme GNU89 "inline": un code visible de l'extérieur est émis, de sorte qu'une unité de traduction au plus puisse 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 triera plusieurs occurrences 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 suivant le modèle gnu89).

119
puetzk

Je crois que vous avez mal compris __FILE__ et __LINE__ en vous basant sur cette déclaration:

car il utilise __FILE__ et Macros __LINE__ qui doivent être résolus pour l'appelant mais pas pour l'appelé une fonction

Il y a plusieurs phases de compilation, et le prétraitement est la première. __FILE__ et __LINE__ sont remplacés pendant cette phase. Donc, au moment où le compilateur peut considérer la fonction d'inline, elle a déjà été remplacée 

29
Don Neufeld

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 obtiendrez des valeurs différentes à chaque fois. Comme Don l'a dit, vous ne le ferez pas, car __FILE__ et __LINE__ sont implémentés par le pré-processeur, mais inline est implémenté par le compilateur. Ainsi, peu importe où vous appelez printLocation, vous obtiendrez le même résultat.

La façon dont uniquement vous permet 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;
...
12
Roddy

La situation avec inline, statique 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 C++). Vous pouvez trouver des informations utiles et détaillées sur ce qu’elles font dans C ici .

3
Simon Howard

Les macros sont votre choix ici plutôt que les fonctions en ligne. Une occasion rare où les macros régissent des 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 <cstdio>
#include <cstring>

#else

#include <stdio.h>
#include <string.h>

#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 séparé, y compris le même, dans chaque fichier c/cc/cxx/cpp. Préférez si possible les fonctions en ligne ou les identifiants const (le cas échéant) aux macros.

2
enthusiasticgeek

Au lieu de répondre "que fait-il?", Je réponds "comment puis-je le faire faire ce que je veux?" Il existe 5 types d'inline, tous disponibles en GNU C89, C99 standard et C++:

toujours en ligne, sauf si l'adresse est prise

Ajoutez __attribute__((always_inline)) à une 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 cela, sauf si vous avez besoin de sa sémantique (par exemple pour affecter l’Assemblée 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")

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

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

inline, mais n'émet aucun symbole (en laissant des références externes)

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

émettre toujours (pour une UE, pour résoudre ce qui précède)

La version suggérée émet un symbole faible en C++, mais un symbole fort dans l’un ou l’autre dialecte de C:

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

Ou vous pouvez le faire sans le soupçon qui émet un symbole fort dans les deux langues:

void foo(void) { ... }

En général, vous savez quelle langue votre TU est lorsque vous fournissez les définitions, et vous n'avez probablement pas besoin de beaucoup d'inline.

en ligne et émettre dans chaque TU

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

Pour tous ceux-ci sauf le static, vous pouvez ajouter une déclaration void foo(void) ci-dessus. Cela aide avec la "meilleure pratique" d'écrire des en-têtes propres, puis #includeer un fichier séparé avec les définitions en ligne. Ensuite, si vous utilisez des inlines de style C, #define une macro d'une manière différente dans un TU dédié pour fournir les définitions out-of-line.

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

0
o11c