106 votes

Est-ce que "inline" sans "static" ou "extern" est utile en C99?

Quand j'essaie de compiler ce code

inline void f() {}

int main()
{
    f();
}

à l'aide de la ligne de commande

gcc -std=c99 -o a a.c

J'obtiens une erreur de l'éditeur de liens (undefined reference to f). L'erreur disparaît si j'utilise static inline ou extern inline au lieu de simplement en inline, ou si je compile avec -O (si la fonction est réellement inline).

Ce comportement semble être définis au paragraphe 6.7.4 (6) de la standard C99:

Si tous les fichiers de la portée des déclarations pour une fonction dans une unité de traduction comprennent l' inline fonction de rédacteur de devis sans extern, puis la définition de l'unité de traduction est une ligne de définition. Une ligne de définition ne fournit pas une définition externe pour la fonction, et n'interdit pas à une définition externe dans une autre unité de traduction. Une ligne de définition offre une alternative à une définition extérieure, un traducteur peut utiliser pour mettre en œuvre tout appel à la fonction dans la même unité de traduction. Il n'est pas précisé si l'appel à la fonction utilise la ligne de définition ou de la définition externe.

Si je comprends correctement, une unité de compilation avec une fonction définie à l' inline comme dans l'exemple ci-dessus ne compile régulièrement si il y a aussi une fonction externe avec le même nom, et je ne sais jamais si mon propre fonction ou la fonction externe est appelée.

N'est-ce pas totalement le comportement de daft? Est-il toujours utile de définir une fonction inline sans static ou extern en C99? Ai-je raté quelque chose?

Résumé des réponses

Bien sûr qu'il me manquait quelque chose, et le comportement n'est pas stupide. :)

Comme Nemo explique, l'idée est de mettre la définition de la fonction

inline void f() {}

dans le fichier d'en-tête et seulement une déclaration

extern inline void f();

dans le correspondant .c fichier. Seulement l' extern déclaration déclenche la génération de visible de l'extérieur en code binaire. Et il y a en effet pas d'utilisation d' inline dans une .c fichier -- il est seulement utile dans les en-têtes.

Comme la justification de la C99 comité de cité dans la réponse de Jonathan explicates, inline est sur tous les optimisations du compilateur qui nécessitent la définition d'une fonction pour être visible sur le site de l'appel. Ce ne peut être atteint que par la mise à la définition de l'en-tête, et bien sûr une définition dans un en-tête ne doit pas émettre de code à chaque fois qu'il est vu par le compilateur. Mais depuis que le compilateur n'est pas forcé de fait une fonction inline, une définition externe doit exister quelque part.

43voto

Nemo Points 32838

En fait, cette excellente réponse également à répondre à votre question, je pense que:

extern inline

L'idée est que "inline" peut être utilisé dans un fichier d'en-tête, puis "extern inline" dans un .c fichier. "extern inline" est juste la façon dont vous indiquer au compilateur quel objet fichier doit contenir le (visible de l'extérieur) du code généré.

[mise à jour, à élaborer]

Je ne pense pas qu'il y est d'aucune utilité "inline" (sans "statique" ou "externe").c fichier. Mais dans un fichier d'en-tête, il a un sens, et il exige un correspondant "extern inline" dans la déclaration de certains .c fichier de réellement générer le stand-alone de code.

28voto

Jonathan Leffler Points 299946

De la norme (ISO/IEC 9899:1999) lui-même:

L'Annexe J. 2 Comportement Indéfini

  • ...
  • Une fonction de liaison externe est déclarée avec un inline fonction de prescripteur, mais n'est pas aussi définie dans la même unité de traduction (6.7.4).
  • ...

Le C99 a écrit une Justification, et il dit:

6.7.4 Fonction des prescripteurs

Une nouvelle fonctionnalité de C99: L' inline mot-clé, adapté à partir de C++, une fonction spécificateurque peut être utilisé seulement dans les déclarations de fonction. Il est utile pour le programme d'optimisations qui nécessitent l' définition d'une fonction pour être visible sur le site de l'appel. (À noter que la Norme n'est pas de tenter de préciser la nature de ces optimisations.)

La visibilité est assurée que si la fonction a une liaison interne, ou si elle a une liaison externe et l'appel est dans la même unité de traduction comme la définition externe. Dans ces cas, la présence de l' inline mot-clé dans une déclaration ou de la définition de la fonction n'a aucun effet au-delà indiquant un la préférence que les appels de cette fonction doit être optimisé, de préférence à des appels à d'autres fonctions déclarées sans le inline mot-clé.

La visibilité est un problème pour un appel d'une fonction de liaison externe où l'appel est dans un différent de l'unité de traduction à partir de la définition de la fonction. Dans ce cas, l' inlinemot-clé permet à l'unité de traduction contenant l'appel à également contenir un local, ou en ligne, la définition de l' fonction.

Un programme peut contenir une unité de traduction avec une définition externe, une unité de traduction avec un inline définition, et une unité de traduction avec une déclaration, mais pas de définition d'une fonction. Appels dans la dernière unité de traduction utilisera la définition externe, comme d'habitude.

Une ligne de définition d'une fonction est considérée comme une définition que l'extérieur définition. Si un appel à une fonction func avec une liaison externe se produit lorsqu'un inline la définition est visible, le comportement est le même que si l'appel ont été faites à une autre fonction, dire __func, avec une liaison interne. Conforme au programme ne doivent pas dépendre de la fonction appelé. C'est la ligne dans le modèle Standard.

Conforme au programme ne doivent pas compter sur la mise en œuvre à l'aide de la ligne de définition, ni il s'appuyer sur la mise en œuvre à l'aide de la définition externe. L'adresse d'une fonction est toujours l'adresse correspondant à la définition externe, mais lorsque cette adresse est utilisée pour appeler le la fonction, la ligne de définition peut être utilisé. Ainsi, l'exemple suivant peut pas se comporter comme prévu.

inline const char *saddr(void)
{
    static const char name[] = "saddr";
    return name;
}
int compare_name(void)
{
    return saddr() == saddr(); // unspecified behavior
}

Depuis la mise en œuvre pourrait utiliser la ligne de définition pour l'un des appels à l' saddr et l'utilisation la définition externe pour les autres, l'égalité n'est pas garanti à évaluer à 1 (vrai). Cela montre que les objets statiques définies au sein de la ligne de définition sont distinctes de leurs objet correspondant à la définition externe. Ceci a motivé la contrainte à l'encontre même de la définition d'un non-const objet de ce type.

Inline a été ajouté à la Norme de telle manière qu'il puisse être mis en œuvre avec l'existant de l'éditeur de liens la technologie, et un sous-ensemble de C99 inline est compatible avec le C++. Ceci a été réalisé en exigeant que exactement une unité de traduction contenant la définition d'une fonction inline être spécifié comme celui qui fournit la définition externe de la fonction. Parce que la spécification se compose simplement d'une déclaration qui soit dépourvu de l' inline mot-clé, ou contient les deux inline et extern, il sera également acceptée par un C++ traducteur.

Inline en C99 ne s'étendent le C++ spécification de deux façons. Tout d'abord, si une fonction est déclarée inline dans une unité de traduction, il n'a pas besoin d'être déclarée inline dans tous les autres de l'unité de traduction. Cela permet, par exemple, une fonction de la bibliothèque qui est à être incorporé au sein de la bibliothèque mais disponible seule une définition externe ailleurs. L'alternative de l'utilisation d'une fonction wrapper pour la fonction externe requiert un autre nom; et il peut également avoir un impact sur les performances si un traducteur n'a pas réellement faire inline substitution.

Ensuite, l'exigence que toutes les définitions d'une fonction inline être "exactement les mêmes" est remplacé par l'exigence que le comportement du programme ne doivent pas dépendre de l'existence d'un l'appel est mis en œuvre avec une visible inline définition ou de la définition extérieure, d'une fonction. Cela permet à une ligne de définition d'être un spécialiste pour son utilisation dans une unité de traduction. Par exemple, la définition externe d'une fonction de bibliothèque peuvent inclure un argument de validation n'est pas nécessaire pour les appels effectués à partir d'autres fonctions dans la même bibliothèque. Ces les extensions offrent quelques avantages; et les programmeurs qui sont préoccupés au sujet de la compatibilité pouvez simplement respecter la plus stricte C++ règles.

Notez qu'il n'est pas approprié pour les implémentations de fournir inline définitions de la norme les fonctions de la bibliothèque dans la norme en-têtes de parce que cela peut casser un code existant redeclares standard des fonctions de la bibliothèque à la suite notamment de leurs en-têtes. L' inline mot-clé est elle vise uniquement à fournir aux utilisateurs avec un portable moyen de suggérer un alignement de fonctions. Parce que le des en-têtes standard n'a pas besoin d'être portable, implémentations ont d'autres options, le long des lignes de:

#define abs(x) __builtin_abs(x)

ou d'autres non-portable mécanismes pour inline standard des fonctions de la bibliothèque.

0voto

larsmans Points 167484

> J'obtiens une erreur de l'éditeur de liens (undefined reference to f)

Les œuvres ici: Linux x86-64, GCC 4.1.2. Peut être un bug dans votre compilateur; je ne vois rien dans le paragraphe cité de la norme qui interdit le programme donné. Notez l'utilisation de si plutôt que de l' iff.

Une ligne de définition fournit une alternative à une définition extérieure, un traducteur peut utiliser pour mettre en œuvre tout appel à la fonction dans la même unité de traduction.

Donc, si vous connaissez le comportement de la fonction f et que vous voulez l'appeler, dans une boucle, vous pouvez copier-coller de sa définition dans un module pour empêcher les appels de fonction; ou, vous pouvez fournir une définition qui, pour l'application du module en cours, est l'équivalent (mais omet de validation de la saisie, ou quel que soit l'optimisation que vous pouvez imaginer). Le compilateur écrivain, cependant, a le choix de l'optimisation de la taille du programme à la place.

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