Le mot-clé «statique» en C a deux significations fondamentalement différentes.
Limiter la portée
Dans ce contexte, «statique» s'associe à «extern» pour contrôler la portée d'un nom de variable ou de fonction. Statique fait que le nom de la variable ou de la fonction n'est disponible que dans une seule unité de compilation et uniquement disponible pour le code qui existe après la déclaration / définition dans le texte de l'unité de compilation.
Cette limitation elle-même ne signifie vraiment que si et seulement si vous avez plusieurs unités de compilation dans votre projet. Si vous n'avez qu'une seule unité de compilation, cela fait toujours des choses, mais ces effets sont pour la plupart inutiles (sauf si vous aimez creuser dans des fichiers objets pour lire ce que le compilateur a généré.)
Comme indiqué, ce mot-clé dans ce contexte s'apparie avec le mot-clé 'extern', qui fait le contraire - en rendant le nom de variable ou de fonction pouvant être lié avec le même nom que celui trouvé dans d'autres unités de compilation. Ainsi, vous pouvez considérer «statique» comme nécessitant que la variable ou le nom soit trouvé dans l'unité de compilation actuelle, tandis que «externe» permet le lien entre les unités de compilation croisée.
Durée de vie statique
La durée de vie statique signifie que la variable existe pendant toute la durée du programme (aussi longue soit-elle). Lorsque vous utilisez 'statique' pour déclarer / définir une variable dans une fonction, cela signifie que la variable est créée quelque temps avant sa première utilisation ( ce qui signifie, chaque fois que je l'ai vécu, que la variable est créée avant le début de main ()) et n'est pas détruite par la suite. Pas même lorsque l'exécution de la fonction est terminée et qu'elle revient à son appelant. Et tout comme les variables de durée de vie statiques déclarées en dehors des fonctions, elles sont initialisées au même moment - avant le début de main () - à un zéro sémantique (si aucune initialisation n'est fournie) ou à une valeur explicite spécifiée, si elle est donnée.
Ceci est différent des variables de fonction de type `` auto '', qui sont créées nouvelles (ou comme si elles étaient nouvelles) chaque fois que la fonction est entrée, puis sont détruites (ou comme si elles étaient détruites) lorsque la fonction se ferme.
Contrairement à l'impact de l'application de «statique» sur une définition de variable en dehors d'une fonction, qui a un impact direct sur sa portée, déclarer une variable de fonction (dans un corps de fonction, évidemment) comme «statique» n'a pas impact sur sa portée. La portée est déterminée par le fait qu'elle a été définie au sein d'un corps de fonction. Les variables de durée de vie statiques définies dans les fonctions ont la même étendue que les autres variables «auto» définies dans les corps de fonction - étendue de la fonction.
Sommaire
Ainsi, le mot clé «statique» a des contextes différents avec ce qui équivaut à «des significations très différentes». La raison pour laquelle il a été utilisé de deux manières, comme celle-ci, était d'éviter d'utiliser un autre mot clé. (Il y a eu une longue discussion à ce sujet.) Il a été estimé que les programmeurs pouvaient tolérer l'utilisation et la valeur d'éviter encore un autre mot-clé dans la langue était plus importante (que les arguments autrement).
(Toutes les variables déclarées en dehors des fonctions ont une durée de vie statique et n'ont pas besoin du mot clé 'statique' pour que cela soit vrai. Donc, ce type de mot clé libéré pour être utilisé ici signifie quelque chose de complètement différent: 'visible uniquement dans une seule compilation "C'est un hack, en quelque sorte.)
Note spécifique
caractère volatile non signé statique PORTB @ 0x06;
Le mot «statique» ici doit être interprété comme signifiant que l'éditeur de liens ne tentera pas de faire correspondre plusieurs occurrences de PORTB qui peuvent être trouvées dans plusieurs unités de compilation (en supposant que votre code en a plusieurs).
Il utilise une syntaxe spéciale (non portable) pour spécifier «l'emplacement» (ou la valeur numérique de l'étiquette qui est généralement une adresse) de PORTB. L'éditeur de liens reçoit donc l'adresse et n'a pas besoin d'en trouver une. Si vous aviez deux unités de compilation utilisant cette ligne, elles finiraient chacune par pointer vers le même endroit, de toute façon. Il n'est donc pas nécessaire de l'étiqueter «extern», ici.
S'ils avaient utilisé «extern», cela pourrait poser un problème. L'éditeur de liens pourrait alors voir (et tenter de faire correspondre) plusieurs références à PORTB trouvées dans plusieurs compilations. Si tous spécifient une adresse comme celle-ci, et que les adresses ne sont PAS les mêmes pour une raison quelconque [erreur?], Alors qu'est-ce que c'est censé faire? Se plaindre? Ou? (Techniquement, avec 'extern' la règle de base serait que seulement UN unité de compilation spécifierait la valeur et les autres ne devraient pas.)
Il est simplement plus facile de l'étiqueter comme `` statique '', en évitant de faire en sorte que l'éditeur de liens s'inquiète des conflits, et il suffit de blâmer toute erreur pour les adresses mal appariées sur quiconque a changé l'adresse en quelque chose qu'elle ne devrait pas être.
Dans les deux cas, la variable est traitée comme ayant une «durée de vie statique». (Et «volatile».)
Une déclaration n'est pas une définition , mais toutes les définitions sont des déclarations
En C, une définition crée un objet. Il le déclare également. Mais une déclaration ne crée généralement pas (voir la puce ci-dessous) un objet.
Voici les définitions et déclarations:
static int a;
static int a = 7;
extern int b = 5;
extern int f() { return 10; }
Les éléments suivants ne sont pas des définitions, mais uniquement des déclarations:
extern int b;
extern int f();
Notez que les déclarations ne créent pas d'objet réel. Ils déclarent uniquement les détails à ce sujet, que le compilateur peut ensuite utiliser pour aider à générer le code correct et à fournir des messages d'avertissement et d'erreur, le cas échéant.
Ci-dessus, je dis «habituellement» à bon escient. Dans certains cas, une déclaration peut créer un objet et est donc promue à une définition par l'éditeur de liens (jamais par le compilateur). Ainsi, même dans ce cas rare, le compilateur C pense toujours que la déclaration n'est qu'une déclaration. C'est la phase de l'éditeur de liens qui fait les promotions nécessaires d'une déclaration. Gardez cela à l'esprit.
Dans les exemples ci-dessus, s'il s'avère qu'il n'y a que des déclarations pour un "extern int b;" dans toutes les unités de compilation liées, l'éditeur de liens est chargé de créer une définition. Sachez qu'il s'agit d'un événement de liaison. Le compilateur est complètement ignorant, lors de la compilation. Elle ne peut être déterminée au moment de la liaison que si une déclaration de ce type est la plus promue.
Le compilateur sait que "static int a;" ne peut pas être promu par l'éditeur de liens au moment du lien, il s'agit donc en fait d'une définition au moment de la compilation .