En C, je n'ai remarqué aucun effet du extern
mot clé utilisé avant la déclaration de fonction. Au début, je pensais que la définition extern int f();
dans un seul fichier vous obligeait à l'implémenter en dehors de la portée du fichier. Cependant, j'ai découvert que les deux:
extern int f();
int f() {return 0;}
et
extern int f() {return 0;}
compilez très bien, sans avertissement de gcc. J'ai utilisé gcc -Wall -ansi
; il n'accepterait même pas les //
commentaires.
Y a-t-il des effets à utiliser extern
avant les définitions de fonction ? Ou est-ce juste un mot-clé facultatif sans effets secondaires pour les fonctions.
Dans ce dernier cas, je ne comprends pas pourquoi les concepteurs standards ont choisi de joncher la grammaire de mots-clés superflus.
EDIT: Pour clarifier les choses, je sais qu'il ya une utilisation pour extern
des variables, mais je demande seulement à propos extern
de fonctions .
Réponses:
Nous avons deux fichiers, foo.c et bar.c.
Voici foo.c
Maintenant, voici bar.c
Comme vous pouvez le voir, nous n'avons pas d'en-tête partagé entre foo.c et bar.c, cependant bar.c a besoin de quelque chose déclaré dans foo.c lorsqu'il est lié, et foo.c a besoin d'une fonction de bar.c lorsqu'il est lié.
En utilisant «extern», vous dites au compilateur que tout ce qui suit sera trouvé (non statique) au moment de la liaison; ne lui réservez rien dans la passe actuelle car il sera rencontré plus tard. Les fonctions et les variables sont traitées de la même manière à cet égard.
C'est très utile si vous avez besoin de partager du global entre les modules et que vous ne voulez pas le mettre / initialiser dans un en-tête.
Techniquement, chaque fonction dans un en-tête public de bibliothèque est «extern», mais leur étiquetage en tant que tel a très peu ou pas d'avantages, selon le compilateur. La plupart des compilateurs peuvent comprendre cela par eux-mêmes. Comme vous le voyez, ces fonctions sont en fait définies ailleurs.
Dans l'exemple ci-dessus, main () afficherait hello world une seule fois, mais continuerait à entrer bar_function (). Notez également que bar_function () ne reviendra pas dans cet exemple (puisqu'il ne s'agit que d'un exemple simple). Imaginez simplement que stop_now soit modifié lorsqu'un signal est desservi (donc volatile) si cela ne semble pas assez pratique.
Les externes sont très utiles pour des choses comme les gestionnaires de signaux, un mutex que vous ne voulez pas mettre dans un en-tête ou une structure, etc. La plupart des compilateurs optimiseront pour s'assurer qu'ils ne réservent aucune mémoire pour des objets externes, car ils savent Je vais le réserver dans le module où l'objet est défini. Cependant, encore une fois, il est inutile de le spécifier avec des compilateurs modernes lors du prototypage de fonctions publiques.
J'espère que cela pourra aider :)
la source
bar.c
et la déclaration dansfoo.c
. Si la fonction est déclarée dansfoo.h
et que les deux fichiers incluentfoo.h
, l'en-tête assure la cohérence entre les deux fichiers source. Sans elle, si la définition debar_function
inbar.c
change mais que la déclaration infoo.c
n'est pas modifiée, alors les choses tournent mal au moment de l'exécution; le compilateur ne peut pas repérer le problème. Avec un en-tête correctement utilisé, le compilateur repère le problème.Pour autant que je me souvienne de la norme, toutes les déclarations de fonctions sont considérées comme "extern" par défaut, il n'est donc pas nécessaire de le spécifier explicitement.
Cela ne rend pas ce mot-clé inutile puisqu'il peut également être utilisé avec des variables (et dans ce cas, c'est la seule solution pour résoudre les problèmes de liaison). Mais avec les fonctions - oui, c'est facultatif.
la source
Vous devez distinguer deux concepts distincts: la définition de fonction et la déclaration de symbole. "extern" est un modificateur de lien, un indice au compilateur sur l'endroit où le symbole auquel il est fait référence par la suite est défini (l'indice est "pas ici").
Si j'écris
dans la portée du fichier (en dehors d'un bloc fonctionnel) dans un fichier C, alors vous dites "la variable peut être définie ailleurs".
est à la fois une déclaration de la fonction f et une définition de la fonction f. La définition dans ce cas l'emporte sur l'externe.
est d'abord une déclaration, suivie de la définition.
L'utilisation de
extern
est incorrecte si vous souhaitez déclarer et définir simultanément une variable d'étendue de fichier. Par exemple,donnera une erreur ou un avertissement, selon le compilateur.
L'utilisation de
extern
est utile si vous souhaitez explicitement éviter la définition d'une variable.Laisse-moi expliquer:
Disons que le fichier ac contient:
Le fichier ah comprend:
et le fichier bc contient:
L'extern dans l'en-tête est utile, car il indique au compilateur pendant la phase de liaison, "c'est une déclaration et non une définition". Si je supprime la ligne dans ac qui définit i, lui alloue de l'espace et lui attribue une valeur, le programme ne devrait pas se compiler avec une référence non définie. Cela indique au développeur qu'il a fait référence à une variable, mais ne l'a pas encore définie. Si par contre, j'omets le mot-clé "extern" et supprime la
int i = 2
ligne, le programme compile toujours - i sera défini avec une valeur par défaut de 0.Les variables d'étendue de fichier sont implicitement définies avec une valeur par défaut de 0 ou NULL si vous ne leur attribuez pas explicitement de valeur, contrairement aux variables d'étendue de bloc que vous déclarez en haut d'une fonction. Le mot-clé extern évite cette définition implicite et permet ainsi d'éviter les erreurs.
Pour les fonctions, dans les déclarations de fonctions, le mot clé est en effet redondant. Les déclarations de fonction n'ont pas de définition implicite.
la source
int i = 2
ligne du troisième paragraphe? Et est-il correct de déclarer, vu queint i;
le compilateur allouera de la mémoire pour cette variable, mais que vuextern int i;
, le compilateur n'allouera PAS de mémoire mais recherchera la variable ailleurs?Le
extern
mot-clé prend différentes formes selon l'environnement. Si une déclaration est disponible, leextern
mot clé prend le lien comme celui spécifié précédemment dans l'unité de traduction. En l'absence d'une telle déclaration,extern
spécifie le lien externe.Voici les paragraphes pertinents du projet C99 (n1256):
la source
Les fonctions en ligne ont des règles spéciales sur ce que
extern
signifie. (Notez que les fonctions en ligne sont une extension C99 ou GNU; elles n'étaient pas dans le C.Pour les fonctions non en ligne,
extern
n'est pas nécessaire car il est activé par défaut.Notez que les règles pour C ++ sont différentes. Par exemple,
extern "C"
est nécessaire sur la déclaration C ++ des fonctions C que vous allez appeler à partir de C ++, et il existe différentes règles à propos deinline
.la source
C'est pourquoi, 10 ans plus tard:
extern
dans la déclaration de fonction pour suppression;git/git
suit cette conclusion et supprimeextern
de son code (pour Git 2.22, Q2 2019).Voir commit ad6dad0 , commit b199d71 , commit 5545442 (29 avril 2019) par Denton Liu (
Denton-L
) .(Fusionné par Junio C Hamano -
gitster
- dans commit 4aeeef3 , 13 mai 2019)Ce n'est cependant pas toujours simple:
Voir commit 7027f50 (04 sept. 2019) par Denton Liu (
Denton-L
) .(Fusionné par Denton Liu -
Denton-L
- dans commit 7027f50 , 05 sept. 2019)Notez qu'avec Git 2.24 (Q4 2019), tout faux
extern
est supprimé.Voir commit 65904b8 (30 septembre 2019) par Emily Shaffer (
nasamuffin
) .Aide: Jeff King (
peff
) .Voir commit 8464f94 (21 sept. 2019) par Denton Liu (
Denton-L
) .Aide: Jeff King (
peff
) .(Fusionné par Junio C Hamano -
gitster
- dans commit 59b19bc , 07 octobre 2019)la source
Le
extern
mot clé informe le compilateur que la fonction ou la variable a un lien externe - en d'autres termes, qu'elle est visible à partir de fichiers autres que celui dans lequel elle est définie. En ce sens, il a la signification opposée austatic
mot - clé. C'est un peu bizarre à mettreextern
au moment de la définition, car aucun autre fichier n'aurait de visibilité sur la définition (ou cela entraînerait plusieurs définitions). Normalement, vous insérezextern
une déclaration à un moment donné avec une visibilité externe (comme un fichier d'en-tête) et mettez la définition ailleurs.la source
déclarer une fonction extern signifie que sa définition sera résolue au moment de la liaison, pas lors de la compilation.
Contrairement aux fonctions régulières, qui ne sont pas déclarées extern, elle peut être définie dans n'importe quel fichier source (mais pas dans plusieurs fichiers source, sinon vous obtiendrez une erreur de l'éditeur de liens indiquant que vous avez donné plusieurs définitions de la fonction), y compris celle dans dont il est déclaré extern. Ainsi, dans votre cas, l'éditeur de liens résout la définition de la fonction dans le même fichier.
Je ne pense pas que cela serait très utile, mais faire de telles expériences donne un meilleur aperçu du fonctionnement du compilateur et de l'éditeur de liens du langage.
la source
La raison pour laquelle cela n'a aucun effet est qu'au moment de la liaison, l'éditeur de liens tente de résoudre la définition externe (dans votre cas
extern int f()
). Peu importe qu'il le trouve dans le même fichier ou dans un fichier différent, tant qu'il est trouvé.J'espère que ça répond à ta question.
la source
extern
à n'importe quelle fonction?