Ma question est de savoir quand une fonction doit être référencée avec le extern
mot - clé en C.
Je ne vois pas quand cela devrait être utilisé dans la pratique. Lorsque j'écris un programme, toutes les fonctions que j'utilise sont disponibles via les fichiers d'en-tête que j'ai inclus. Alors, pourquoi serait-il utile d' extern
avoir accès à quelque chose qui n'était pas exposé dans le fichier d'en-tête?
Je pourrais penser à comment extern
fonctionne mal, et si c'est le cas, veuillez me corriger.
Edit: Devriez-vous extern
quelque chose quand c'est la déclaration par défaut sans le mot-clé dans un fichier d'en-tête?
Réponses:
"
extern
" modifie la liaison. Avec le mot-clé, la fonction / variable est supposée être disponible ailleurs et la résolution est reportée à l'éditeur de liens.Il y a une différence entre "extern" sur les fonctions et sur les variables: sur les variables, il n'instancie pas la variable elle-même, c'est-à-dire qu'il n'alloue aucune mémoire. Cela doit être fait ailleurs. Il est donc important si vous souhaitez importer la variable ailleurs. Pour les fonctions, cela indique uniquement au compilateur que la liaison est externe. Comme il s'agit de la valeur par défaut (vous utilisez le mot clé "statique" pour indiquer qu'une fonction n'est pas liée à l'aide d'une liaison externe), vous n'avez pas besoin de l'utiliser explicitement.
la source
extern indique au compilateur que ces données sont définies quelque part et seront connectées avec l'éditeur de liens.
Avec l'aide des réponses ici et en parlant à quelques amis, voici l'exemple pratique d'une utilisation de extern .
Exemple 1 - pour montrer un piège:
Si myCFile1.o et myCFile2.o sont liés, chacun des fichiers c a des copies distinctes de errno . C'est un problème car le même errno est censé être disponible dans tous les fichiers liés.
Exemple 2 - Le correctif.
Maintenant, si myCFile1.o et MyCFile2.o sont liés par l'éditeur de liens, ils pointeront tous deux vers le même errno . Ainsi, résoudre l'implémentation avec extern .
la source
-Wall
et-pedantic
. Pourquoi ? et comment ?Il a déjà été indiqué que le
extern
mot-clé est redondant pour les fonctions.Quant aux variables partagées entre les unités de compilation, vous devez les déclarer dans un fichier d'en-tête avec le mot-clé extern, puis les définir dans un seul fichier source, sans le mot-clé extern. Le fichier source unique doit être celui qui partage le nom du fichier d'en-tête, pour une meilleure pratique.
la source
Plusieurs années plus tard, je découvre cette question. Après avoir lu chaque réponse et commentaire, j'ai pensé pouvoir clarifier quelques détails ... Cela pourrait être utile pour les personnes qui arrivent ici via la recherche Google.
La question concerne spécifiquement l'utilisation des fonctions "extern", donc j'ignorerai l'utilisation de "extern" avec des variables globales.
Définissons 3 prototypes de fonctions:
Le fichier d'en-tête peut être utilisé par le code source principal comme suit:
Afin de compiler et de lier, nous devons définir "function_2" dans le même fichier de code source où nous appelons cette fonction. Les deux autres fonctions peuvent être définies dans un code source différent " .C" ou peuvent se trouver dans n'importe quel fichier binaire ( .OBJ, * .LIB, * .DLL), pour lequel nous n'avons peut-être pas le code source.
Incluons à nouveau l'en-tête "mon_projet.H" dans un autre fichier "* .C" pour mieux comprendre la différence. Dans le même projet, nous ajoutons le fichier suivant:
Caractéristiques importantes à noter:
Lorsqu'une fonction est définie comme "statique" dans un fichier d'en-tête, le compilateur / éditeur de liens doit trouver une instance d'une fonction portant ce nom dans chaque module qui utilise ce fichier d'inclusion.
Une fonction qui fait partie de la bibliothèque C peut être remplacée dans un seul module en redéfinissant un prototype avec "statique" uniquement dans ce module. Par exemple, remplacez tout appel à «malloc» et «free» pour ajouter une fonction de détection de fuite de mémoire.
Le spécificateur "extern" n'est pas vraiment nécessaire pour les fonctions. Lorsque "statique" n'est pas trouvé, une fonction est toujours supposée être "externe".
Cependant, "extern" n'est pas la valeur par défaut pour les variables. Normalement, tout fichier d'en-tête qui définit les variables pour être visible sur de nombreux modules doit utiliser "extern". La seule exception serait si un fichier d'en-tête est garanti d'être inclus à partir d'un et d'un seul module.
De nombreux chefs de projet exigeraient alors que cette variable soit placée au début du module, et non dans un fichier d'en-tête. Certains grands projets, comme l'émulateur de jeu vidéo "Mame", exigent même que cette variable n'apparaisse qu'au-dessus de la première fonction qui les utilise.
la source
En C, 'extern' est implicite pour les prototypes de fonctions, car un prototype déclare une fonction qui est définie ailleurs. En d'autres termes, un prototype de fonction a une liaison externe par défaut; utiliser «extern» est bien, mais est redondant.
(Si une liaison statique est requise, la fonction doit être déclarée comme "statique" à la fois dans son prototype et son en-tête de fonction, et ceux-ci doivent normalement être tous deux dans le même fichier .c).
la source
Un très bon article que je suis venu sur le
extern
mot - clé, avec les exemples: http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/Bien que je ne convienne pas que l'utilisation
extern
de déclarations de fonction soit redondante. Ceci est censé être un paramètre de compilation. Je recommande donc d'utiliser lesextern
déclarations de fonction lorsque cela est nécessaire.la source
Si chaque fichier de votre programme est d'abord compilé dans un fichier objet, alors les fichiers objet sont liés ensemble, vous en avez besoin
extern
. Il dit au compilateur "Cette fonction existe, mais le code pour elle est ailleurs. Ne paniquez pas."la source
Toutes les déclarations de fonctions et de variables dans les fichiers d'en-tête doivent être
extern
.Les exceptions à cette règle sont les fonctions en ligne définies dans l'en-tête et les variables qui - bien que définies dans l'en-tête - devront être locales à l'unité de traduction (le fichier source dans lequel l'en-tête est inclus): elles devraient l'être
static
.Dans les fichiers source,
extern
ne doit pas être utilisé pour les fonctions et variables définies dans le fichier. Juste préfixez les définitions locales avecstatic
et ne faites rien pour les définitions partagées - ce seront des symboles externes par défaut.La seule raison à utiliser
extern
dans un fichier source est de déclarer des fonctions et des variables qui sont définies dans d'autres fichiers source et pour lesquelles aucun fichier d'en-tête n'est fourni.La déclaration de prototypes de fonction
extern
n'est en fait pas nécessaire. Certaines personnes ne l'aiment pas, car cela ne fera que gaspiller de l'espace et les déclarations de fonction ont déjà tendance à déborder des limites de ligne. D'autres l'aiment parce que de cette façon, les fonctions et les variables peuvent être traitées de la même manière.la source
extern
est facultatif pour les déclarations de fonctions, mais j'aime traiter les variables et les fonctions de la même manière - au moins c'est la chose la plus raisonnable que j'ai pu trouver, car je ne me souviens pas exactement pourquoi j'ai commencé à faire cela;)Les fonctions réellement définies dans d'autres fichiers source ne doivent être déclarées que dans les en-têtes. Dans ce cas, vous devez utiliser extern lors de la déclaration du prototype dans un en-tête.
La plupart du temps, vos fonctions seront l'une des suivantes (plus comme une meilleure pratique):
la source
Lorsque vous avez cette fonction définie sur une autre DLL ou bibliothèque, de sorte que le compilateur se reporte à l'éditeur de liens pour le trouver. Le cas typique est lorsque vous appelez des fonctions à partir de l'API OS.
la source