Quelle est la différence entre la fonction «statique» et «statique en ligne»?

123

L'OMI fait tous les deux la fonction d'avoir une portée de l'unité de traduction uniquement.

Quelle est la différence entre la fonction "statique" et "statique en ligne"?

Pourquoi devrait inlineêtre mis dans un fichier d'en-tête, pas dans un .cfichier?

new_perl
la source

Réponses:

109

inlineindique au compilateur d' essayer d' incorporer le contenu de la fonction dans le code appelant au lieu d'exécuter un appel réel.

Pour les petites fonctions appelées fréquemment qui peuvent faire une grande différence de performances.

Cependant, ce n'est qu'un "indice", et le compilateur peut l'ignorer, et la plupart des compilateurs essaieront de "insérer" même lorsque le mot-clé n'est pas utilisé, dans le cadre des optimisations, lorsque c'est possible.

par exemple:

static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};

Cette boucle serrée effectuera un appel de fonction à chaque itération, et le contenu de la fonction est en fait nettement inférieur au code que le compilateur doit mettre pour effectuer l'appel. inlinedemandera essentiellement au compilateur de convertir le code ci-dessus en un équivalent de:

 int i;
 ....
 for (i=0; i<999999; i = i+1) { /* do something here */};

Sauter l'appel et le retour de la fonction réelle

Évidemment, c'est un exemple pour montrer le point, pas un vrai morceau de code.

staticfait référence à la portée. En C, cela signifie que la fonction / variable ne peut être utilisée que dans la même unité de traduction.

littleadv
la source
4
Non, staticfait référence à la portée. En C, cela signifie que la fonction / variable ne peut être utilisée que dans la même unité de traduction.
littleadv
8
Il est également important de noter que le code déclaré comme inline appartient à l'en-tête, alors que le code source normal (non-modèle) ne peut pas entrer dans les en-têtes sans provoquer de multiples erreurs de redéfinition. Ainsi, même lorsque vous déclarez quelque chose en ligne, même si le compilateur choisit de ne pas l'inclure, il existe toujours une redéfinition multiple standard obligatoire pour éviter un comportement qui entre en jeu.
VoidStar
13
@VoidStar En fait static(avec ou sans inline) peut être parfaitement bien dans l'en-tête, ne voyez aucune raison pourquoi pas. Les modèles sont pour C ++, cette question concerne C.
littleadv
2
@littleadv: la principale raison de mettre des définitions de fonction dans des fichiers d'en-tête est de les rendre inlinables, donc les marquer explicitement inlineest un bon style, imo
Christoph
9
En fait , inlinene pas donner des instructions au compilateur de faire toute tentative de inline. Il permet simplement au programmeur d'inclure le corps de la fonction dans plusieurs unités de traduction sans violation de l'ODR. Un effet secondaire de ceci est que cela permet au compilateur, quand il mettrait en ligne la fonction, de le faire.
Ruslan
96

Par défaut, une définition en ligne n'est valide que dans l'unité de traduction actuelle.

Si la classe de stockage est extern, l'identificateur a une liaison externe et la définition en ligne fournit également la définition externe.

Si la classe de stockage est static, l'identifiant a une liaison interne et la définition en ligne est invisible dans les autres unités de traduction.

Si la classe de stockage n'est pas spécifiée, la définition en ligne n'est visible que dans l'unité de traduction actuelle, mais l'identifiant a toujours un lien externe et une définition externe doit être fournie dans une unité de traduction différente. Le compilateur est libre d'utiliser la définition en ligne ou externe si la fonction est appelée dans l'unité de traduction actuelle.

Comme le compilateur est libre d'insérer (et non en ligne) toute fonction dont la définition est visible dans l'unité de traduction actuelle (et, grâce aux optimisations de temps de liaison, même dans différentes unités de traduction, bien que le standard C ne prenne pas vraiment en compte that), dans la plupart des cas, il n'y a aucune différence entre les définitions de fonction staticet static inline.

Le inlinespécificateur (comme la registerclasse de stockage) n'est qu'un indice du compilateur, et le compilateur est libre de l'ignorer complètement. Les compilateurs non optimisés conformes aux normes n'ont qu'à honorer leurs effets secondaires, et les compilateurs d'optimisation feront ces optimisations avec ou sans conseils explicites.

inlineet registerne sont pas inutiles, cependant, car ils demandent au compilateur de lancer des erreurs lorsque le programmeur écrit du code qui rendrait les optimisations impossibles: une inlinedéfinition externe ne peut pas référencer des identifiants avec un lien interne (car ils ne seraient pas disponibles dans une unité de traduction différente) ou définissez des variables locales modifiables avec une durée de stockage statique (car elles ne partageraient pas l'état entre les unités de traduction), et vous ne pouvez pas prendre d'adresses de registervariables qualifiées.

Personnellement, j'utilise également la convention pour marquer staticles définitions de fonctions dans les en-têtes inline, car la principale raison pour laquelle les définitions de fonctions sont placées dans les fichiers d'en-tête est de les rendre inlinables.

En général, je n'utilise que des définitions de static inlinefonction et d' static constobjet en plus des externdéclarations dans les en-têtes.

Je n'ai jamais écrit de inlinefonction avec une classe de stockage différente de static.

Christoph
la source
8
C'est la bonne réponse. Toute réponse dont on parle inlinecomme si elle s'appliquait réellement à l'inlining est trompeuse et sans doute incorrecte. Aucun compilateur moderne ne l'utilise comme un indice pour l'inline ou l'exige afin d'activer l'inlining d'une fonction.
Tyg13
1
voté pour "utiliser la convention pour marquer les définitions de fonctions statiques dans les en-têtes en ligne".
John Z. Li
J'ai lu votre réponse en entier et je ne comprends toujours pas la différence sémantique entre staticet static inline. Les deux rendent la définition invisible aux autres unités de traduction. Alors, quelle serait une raison raisonnable d'écrire à la static inlineplace static?
user541686
21

D'après mon expérience avec GCC, je le sais staticet static inlinediffère en quelque sorte de la manière dont le compilateur émet des avertissements sur les fonctions inutilisées. Plus précisément, lorsque vous déclarez une staticfonction et qu'elle n'est pas utilisée dans l'unité de traduction actuelle, le compilateur produit un avertissement concernant une fonction inutilisée, mais vous pouvez empêcher cet avertissement en le changeant en static inline.

Ainsi, j'ai tendance à penser que cela staticdevrait être utilisé dans les unités de traduction et bénéficier d'un compilateur de vérification supplémentaire pour trouver les fonctions inutilisées. Et static inlinedevrait être utilisé dans les fichiers d'en-tête pour fournir des fonctions qui peuvent être intégrées (en raison de l'absence de lien externe) sans émettre d'avertissements.

Malheureusement, je ne trouve aucune preuve de cette logique. Même à partir de la documentation de GCC, je n'ai pas pu conclure que cela inlineinhibe les avertissements de fonction inutilisés. J'apprécierais si quelqu'un partageait des liens vers une description de cela.

seulement
la source
1
Mmm, toujours obtenu warning: unused function 'function' [clang-diagnostic-unused-function]pour une static inlinefonction lors de la construction avec clang-tidy(v8.0.1), qui est utilisée dans une autre unité de traduction. Mais certainement, c'est l'une des meilleures explications et raison de combiner static& inline!
DrumM
6

En C, static signifie que la fonction ou la variable que vous définissez ne peut être utilisée que dans ce fichier (c'est-à-dire l'unité de compilation)

Alors, static inline signifie la fonction en ligne qui ne peut être utilisée que dans ce fichier.

ÉDITER:

L'unité de compilation doit être l' unité de traduction

shengy
la source
2
Ou en termes fantaisistes: il a un lien interne.
K-ballo
@AlokSave: Y a-t-il une différence entre l' unité de compilation et l' unité de traduction ? Si oui, lequel est le plus approprié dans le contexte du langage C ++?
legends2k
Je crois que the compile unitc'est quelque chose que j'ai écrit par erreur, il n'y a rien de tel, la terminologie réelle esttranslation unit
shengy
Votre réponse n'est pas complète car elle est principalement utilisée dans les fichiers d'en-tête, dans les unités de traduction.
DrumM le
5

Une différence qui n'est pas au niveau du langage mais au niveau de l'implémentation populaire: certaines versions de gcc supprimeront les static inlinefonctions non référencées de la sortie par défaut, mais conserveront les staticfonctions simples même si elles ne sont pas référencées. Je ne sais pas à quelles versions cela s'applique, mais d'un point de vue pratique, cela signifie qu'il peut être judicieux de toujours utiliser inlinepour les staticfonctions dans les en-têtes.

R .. GitHub STOP AIDING ICE
la source
Qu'en est-il de l'utilisation inlinedans la définition? Voulez-vous également ne pas l'utiliser pour les externfonctions?
new_perl
Est-ce toujours vrai avec la version récente de GCC? Votre réponse serait beaucoup plus intéressante si vous donniez un exemple et listiez la version de GCC qui le fait.
Z boson
@Zboson: Je n'ai pas cette information facilement disponible et je n'ai pas le temps de configurer et de tester beaucoup de versions de gcc pour le moment, mais je suis d'accord que ce serait une information utile. Vous pourriez probablement trouver quand gcc a commencé à optimiser pour la première fois les fonctions / objets statiques inutilisés en examinant l'historique de attribute((used))et son utilisation pour permettre à asm de référencer des staticfonctions et des données autrement non référencées .
R .. GitHub STOP HELPING ICE