Quand j'essaye de construire ce code
inline void f() {}
int main()
{
f();
}
en utilisant la ligne de commande
gcc -std=c99 -o a a.c
J'obtiens une erreur de l'éditeur de liens (référence non définie à f
). L'erreur disparaît si j'utilise static inline
ou extern inline
au lieu de just inline
, ou si je compile avec -O
(la fonction est donc en fait en ligne).
Ce comportement semble être défini au paragraphe 6.7.4 (6) de la norme C99:
Si toutes les déclarations de portée de fichier pour une fonction dans une unité de traduction incluent le
inline
spécificateur de fonction sansextern
, alors la définition dans cette unité de traduction est une définition en ligne. Une définition en ligne ne fournit pas de définition externe pour la fonction et n'interdit pas une définition externe dans une autre unité de traduction. Une définition en ligne fournit une alternative à une définition externe, qu'un traducteur peut utiliser pour implémenter tout appel à la fonction dans la même unité de traduction. Il n'est pas spécifié si un appel à la fonction utilise la définition en ligne ou la définition externe.
Si je comprends bien tout cela, une unité de compilation avec une fonction définie inline
comme dans l'exemple ci-dessus ne compile de manière cohérente que s'il existe également une fonction externe avec le même nom, et je ne sais jamais si ma propre fonction ou la fonction externe est appelée.
Ce comportement n'est-il pas complètement idiot? Est-il jamais utile de définir une fonction inline
sans static
ou extern
en C99? Est-ce que je manque quelque chose?
Résumé des réponses
Bien sûr, il me manquait quelque chose et le comportement n'est pas idiot. :)
Comme l' explique Nemo , 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 fichier .c correspondant. Seule la extern
déclaration déclenche la génération de code binaire visible de l'extérieur. Et il n'y a en effet aucune utilisation de inline
dans un fichier .c - il n'est utile que dans les en-têtes.
Comme l'explique la logique du comité C99 citée dans la réponse de Jonathan , il inline
s'agit d'optimisations du compilateur qui nécessitent la définition d'une fonction pour être visible sur le site d'un appel. Ceci ne peut être réalisé qu'en mettant la définition dans 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'elle est vue par le compilateur. Mais puisque le compilateur n'est pas obligé de réellement insérer une fonction, une définition externe doit exister quelque part.
inline
sansstatic
etextern
, cependant. Malheureusement, aucune de ces questions n'est abordée dans cette question.Réponses:
En fait, cette excellente réponse répond également à votre question, je pense:
Que fait extern inline?
L'idée est que "inline" peut être utilisé dans un fichier d'en-tête, puis "extern inline" dans un fichier .c. "extern inline" est juste la façon dont vous indiquez au compilateur quel fichier objet doit contenir le code généré (visible de l'extérieur).
[mettre à jour, pour élaborer]
Je ne pense pas qu'il y ait une quelconque utilité pour "inline" (sans "static" ou "extern") dans un fichier .c. Mais dans un fichier d'en-tête, cela a du sens, et il faut une déclaration "extern inline" correspondante dans un fichier .c pour générer réellement le code autonome.
la source
inline void f() {}
dans l'en-tête etextern inline void f();
dans le fichier .c? Donc, la définition de la fonction réelle va dans l'en-tête et le fichier .c contient une simple déclaration dans ce cas, en inversant l'ordre habituel?inline
sansstatic
ouextern
. Bien sûr,static inline
c'est bien, mais ce n'est pas le sujet de cette question et réponse.-std=c99
place de-std=gnu89
.D'après la norme (ISO / CEI 9899: 1999) elle-même:
Le comité C99 a rédigé une justification , et il dit:
la source
> J'obtiens une erreur de l'éditeur de liens (référence non définie àf
)Fonctionne ici: Linux x86-64, GCC 4.1.2. Peut-être un bogue dans votre compilateur; Je ne vois rien dans le paragraphe cité de la norme qui interdit le programme donné. Notez l'utilisation de if plutôt que d' iff .Ainsi, si vous connaissez le comportement de la fonction
f
et que vous souhaitez l'appeler en boucle serrée, vous pouvez copier-coller sa définition dans un module pour empêcher les appels de fonction; ou , vous pouvez fournir une définition qui, pour les besoins du module actuel, est équivalente (mais ignore la validation d'entrée, ou toute optimisation que vous pouvez imaginer). Le rédacteur du compilateur, cependant, a la possibilité d'optimiser la taille du programme à la place.la source