Que signifie «statique» en C?

J’ai vu le mot static utilisé à différents endroits dans le code C; Est-ce comme une fonction / classe statique en C # (où l’implémentation est partagée entre les objects)?

  1. Une variable statique dans une fonction conserve sa valeur entre les invocations.
  2. Une variable globale statique ou une fonction est “vue” uniquement dans le fichier dans lequel elle est déclarée

(1) est le sujet le plus étranger si vous êtes un débutant, alors voici un exemple:

 #include  void foo() { int a = 10; static int sa = 10; a += 5; sa += 5; printf("a = %d, sa = %d\n", a, sa); } int main() { int i; for (i = 0; i < 10; ++i) foo(); } 

Cela imprime:

 a = 15, sa = 15 a = 15, sa = 20 a = 15, sa = 25 a = 15, sa = 30 a = 15, sa = 35 a = 15, sa = 40 a = 15, sa = 45 a = 15, sa = 50 a = 15, sa = 55 a = 15, sa = 60 

Ceci est utile dans les cas où une fonction doit conserver un état entre les invocations et que vous ne voulez pas utiliser de variables globales. Attention cependant, cette fonctionnalité doit être utilisée avec parcimonie - cela rend votre code non sûr et plus difficile à comprendre.

(2) Est largement utilisé comme fonctionnalité de "contrôle d'access". Si vous avez un fichier .c implémentant certaines fonctionnalités, il ne présente généralement que quelques fonctions "publiques" aux utilisateurs. Le rest de ses fonctions devrait être static afin que l'utilisateur ne puisse pas y accéder. C'est une encapsulation, une bonne pratique.

Citant Wikipedia :

Dans le langage de programmation C, static est utilisé avec des variables globales et des fonctions pour définir leur étendue sur le fichier contenant. Dans les variables locales, static est utilisé pour stocker la variable dans la mémoire allouée de manière statique au lieu de la mémoire allouée automatiquement. Bien que le langage ne dicte pas l'implémentation de chaque type de mémoire, la mémoire allouée de manière statique est généralement réservée dans le segment de données du programme au moment de la compilation, tandis que la mémoire allouée automatiquement est normalement une stack d'appels transitoire.

Voir ici et ici pour plus de détails.

Et pour répondre à votre deuxième question, ce n'est pas comme en C #.

En C ++, cependant, static est également utilisé pour définir des atsortingbuts de classe (partagés entre tous les objects de la même classe) et des méthodes. En C, il n'y a pas de classes, donc cette fonctionnalité est sans importance.

Il y a une autre utilisation non couverte ici, qui fait partie d’une déclaration de type tableau en tant qu’argument d’une fonction:

 int someFunction(char arg[static 10]) { ... } 

Dans ce contexte, cela spécifie que les arguments transmis à cette fonction doivent être un tableau de type char avec au moins 10 éléments. Pour plus d’informations, voir ma question ici .

Réponse courte … ça dépend.

  1. Les variables locales définies statiquement ne perdent pas leur valeur entre les appels de fonction. En d’autres termes, ce sont des variables globales, mais elles correspondent à la fonction locale dans laquelle elles sont définies.

  2. Les variables globales statiques ne sont pas visibles en dehors du fichier C dans lequel elles sont définies.

  3. Les fonctions statiques ne sont pas visibles en dehors du fichier C dans lequel elles sont définies.

Exemple de scope variable multi-fichier

ac :

 #include  /* Undefined behavior: already defined in main. Binutils 2.24 gives an error and refuses to link. https://stackoverflow.com/questions/27667277/why-does-borland-comstack-with-multiple-definitions-of-same-object-in-different-c */ /*int i = 0;*/ /* Works in GCC as an extension: https://stackoverflow.com/a/3692486/895245 */ /*int i;*/ /* OK: extern. Will use the one in main. */ extern int i; /* OK: only visible to this file. */ static int si = 0; void a() { i++; si++; puts("a()"); printf("i = %d\n", i); printf("si = %d\n", si); puts(""); } 

main.c :

 #include  int i = 0; static int si = 0; void a(); void m() { i++; si++; puts("m()"); printf("i = %d\n", i); printf("si = %d\n", si); puts(""); } int main() { m(); m(); a(); a(); return 0; } 

Compilation :

 gcc -c ac -o ao gcc -c main.c -o main.o gcc -o main main.o ao 

Sortie :

 m() i = 1 si = 1 m() i = 2 si = 2 a() i = 3 si = 1 a() i = 4 si = 2 

Interprétation

  • il y a deux variables distinctes pour si , une pour chaque fichier
  • il y a une seule variable partagée pour i

Comme d’habitude, plus la scope est petite, mieux c’est: déclarez toujours les variables static si vous le pouvez.

En programmation C, les fichiers sont souvent utilisés pour représenter des “classes”, et static variables static représentent des membres statiques privés de la classe.

Quelles normes en parlent

C99 N1256 draft 6.7.1 ” Spécificateurs de classe de stockage” indique que static est un “spécificateur de classe de stockage”.

6.2.2 / 3 “Liens des identifiants”: static implique internal linkage :

Si la déclaration d’un identificateur de scope de fichier pour un object ou une fonction contient le spécificateur de classe de stockage statique, l’identificateur a un lien interne.

et 6.2.2 / 2 dit que internal linkage se comporte comme dans notre exemple:

Dans l’ensemble des unités de traduction et des bibliothèques qui constituent un programme complet, chaque déclaration d’un identifiant particulier avec un lien externe désigne le même object ou la même fonction. Dans une unité de traduction, chaque déclaration d’un identifiant avec un lien interne indique le même object ou la même fonction.

où “l’unité de traduction est un fichier source après le prétraitement.

Comment GCC l’implémente pour ELF (Linux)?

Avec la liaison STB_LOCAL .

Si nous compilons:

 int i = 0; static int si = 0; 

et démonter la table des symboles avec:

 readelf -s main.o 

la sortie contient:

 Num: Value Size Type Bind Vis Ndx Name 5: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 si 10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 i 

La liaison est donc la seule différence significative entre eux. Value est juste leur décalage dans la section .bss , nous nous attendons donc à ce qu’elle diffère.

STB_LOCAL est documenté sur la spécification ELF à l’ adresse http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :

STB_LOCAL Les symboles locaux ne sont pas visibles en dehors du fichier object contenant leur définition. Les symboles locaux du même nom peuvent exister dans plusieurs fichiers sans interférer les uns avec les autres

ce qui en fait un choix parfait pour représenter la static .

Les variables sans statique sont STB_GLOBAL , et la spécification dit:

Lorsque l’éditeur de liens combine plusieurs fichiers objects relogeables, il ne permet pas de définitions multiples de symboles STB_GLOBAL portant le même nom.

qui est cohérent avec les erreurs de lien sur plusieurs définitions non statiques.

Si nous augmentons l’optimisation avec -O3 , le symbole si est entièrement supprimé de la table des symboles: il ne peut de toute façon pas être utilisé de l’extérieur. TODO pourquoi conserver les variables statiques sur la table des symboles quand il n’y a pas d’optimisation? Peuvent-ils être utilisés pour quelque chose? Peut-être pour le débogage.

Voir également

  • analogue pour static fonctions static : https://stackoverflow.com/a/30319812/895245
  • comparer static avec extern , ce qui fait “le contraire”: comment utiliser extern pour partager des variables entre des fichiers sources?

Essayez vous-même

Exemple sur github avec lequel vous pouvez jouer.

Ça dépend:

 int foo() { static int x; return ++x; } 

La fonction renvoie 1, 2, 3, etc. — la variable n’est pas sur la stack.

ac:

 static int foo() { } 

Cela signifie que cette fonction n’a de scope que dans ce fichier. Ainsi, ac et bc peuvent avoir des foo() différents, et foo n’est pas exposé aux objects partagés. Donc, si vous avez défini foo in ac, vous ne pouvez pas y accéder depuis bc ou depuis d’autres endroits.

Dans la plupart des bibliothèques C, toutes les fonctions “privées” sont statiques et la plupart “publiques” ne le sont pas.

Les gens continuent à dire que «statique» en C a deux sens. Je propose une autre façon de le voir qui lui donne un sens unique:

  • Appliquer ‘static’ à un élément oblige cet élément à avoir deux propriétés: (a) il n’est pas visible en dehors de la scope actuelle; (b) il est persistant.

La raison pour laquelle il semble avoir deux significations est que, dans C, chaque élément sur lequel «static» peut être appliqué a déjà l’une de ces deux propriétés , il semble donc que cet usage particulier ne concerne que l’autre.

Par exemple, considérez les variables. Les variables déclarées en dehors des fonctions ont déjà une persistance (dans le segment de données). Par conséquent, appliquer “static” ne peut que les rendre non visibles en dehors de la scope actuelle (unité de compilation). Au contraire, les variables déclarées à l’intérieur des fonctions n’ont pas de visibilité en dehors de la

Appliquer ‘static’ aux fonctions est comme l’appliquer aux variables globales – le code est nécessairement persistant (au moins dans le langage), de sorte que seule la visibilité peut être modifiée.

REMARQUE: Ces commentaires s’appliquent uniquement à C. En C ++, appliquer «statique» aux méthodes de classe donne vraiment une signification différente au mot-clé. De même pour l’extension d’argument de tableau C99.

static signifie différentes choses dans différents contextes.

  1. Vous pouvez déclarer une variable statique dans une fonction C. Cette variable n’est visible que dans la fonction, mais elle se comporte comme un global car elle n’est initialisée qu’une fois et conserve sa valeur. Dans cet exemple, chaque fois que vous appelez foo() il affiche un nombre croissant. La variable statique est initialisée une seule fois.

     void foo () { static int i = 0; printf("%d", i); i++ } 
  2. Une autre utilisation de static est lorsque vous implémentez une fonction ou une variable globale dans un fichier .c mais que vous ne voulez pas que son symbole soit visible en dehors du .obj généré par le fichier. par exemple

     static void foo() { ... } 

De Wikipedia:

Dans le langage de programmation C, static est utilisé avec des variables globales et des fonctions pour définir leur étendue sur le fichier contenant. Dans les variables locales, static est utilisé pour stocker la variable dans la mémoire allouée de manière statique au lieu de la mémoire allouée automatiquement. Bien que le langage ne dicte pas l’implémentation de chaque type de mémoire, la mémoire allouée de manière statique est généralement réservée dans le segment de données du programme au moment de la compilation, tandis que la mémoire allouée automatiquement est normalement une stack d’appels transitoire.

Je déteste répondre à une vieille question, mais je ne pense pas que quiconque ait mentionné comment K & R l’explique dans la section A4.1 du “Langage de programmation C”.

En bref, le mot statique est utilisé avec deux significations:

  1. Statique est l’une des deux classes de stockage (l’autre étant automatique). Un object statique conserve sa valeur entre les invocations. Les objects déclarés en dehors de tous les blocs sont toujours statiques et ne peuvent être rendus automatiques.
  2. Mais, lorsque le mot-clé static (qui met l’accent sur l’utilisation du code comme mot-clé) est utilisé avec une déclaration, il donne un lien interne à cet object et ne peut donc être utilisé que dans cette unité de traduction. Mais si le mot-clé est utilisé dans une fonction, il modifie la classe de stockage de l’object (l’object n’est de toute façon visible que dans cette fonction). Le contraire de static est le mot-clé extern , qui donne un lien externe à un object.

Peter Van Der Linden donne ces deux significations dans “Expert C Programming”:

  • Dans une fonction, conserve sa valeur entre les appels.
  • Au niveau de la fonction, visible uniquement dans ce fichier.

Si vous déclarez une variable dans une fonction statique, sa valeur ne sera pas stockée dans la stack des appels de fonction et sera toujours disponible lorsque vous appelez à nouveau la fonction.

Si vous déclarez une variable globale statique, sa scope sera limitée au fichier dans lequel vous l’avez déclarée. Ceci est légèrement plus sûr qu’un global standard qui peut être lu et modifié tout au long de votre programme.

En C, la statique a deux significations, en fonction de la scope de son utilisation. Dans la scope globale, lorsqu’un object est déclaré au niveau du fichier, cela signifie que cet object est uniquement visible dans ce fichier.

Dans tout autre domaine, il déclare un object qui conservera sa valeur entre les différents moments où la scope particulière est entrée. Par exemple, si un int est envoyé dans une procédure:

 void procedure(void) { static int i = 0; i++; } 

la valeur de «i» est initialisée à zéro lors du premier appel à la procédure et la valeur est conservée chaque fois que la procédure est appelée. si “i” était imprimé, cela donnerait une séquence de 0, 1, 2, 3, …

Si vous déclarez cela dans un fichier mytest.c:

 static int my_variable; 

Ensuite, cette variable ne peut être vue que depuis ce fichier. La variable ne peut être exscope nulle part ailleurs.

Si vous déclarez à l’intérieur d’une fonction, la valeur de la variable conservera sa valeur à chaque appel de la fonction.

Une fonction statique ne peut pas être exscope depuis l’extérieur du fichier. Donc, dans un fichier * .c, vous masquez les fonctions et les variables si vous les déclarez statiques.

Il est important de noter que les variables statiques des fonctions sont initialisées à la première entrée de cette fonction et persistent même après la fin de leur appel. dans le cas de fonctions récursives, la variable statique n’est initialisée qu’une seule fois et persiste également sur tous les appels récursifs et même après la fin de l’appel de la fonction.

Si la variable a été créée en dehors d’une fonction, cela signifie que le programmeur ne peut utiliser que la variable dans le fichier source dont la variable a été déclarée.

Notez également que static peut être utilisé de 4 manières différentes.

 to create permanent storage for local variables in a function. to specify internal linkage. to declare member functions that act like non-member functions. to create a single copy of a data member. 

Une variable statique est une variable spéciale que vous pouvez utiliser dans une fonction. Elle enregistre les données entre les appels et ne les supprime pas entre les appels. Par exemple:

 void func(){ static int count; // If you don't declare its value, the value automatically initializes to zero printf("%d, ", count); count++; } void main(){ while(true){ func(); } } 

Le résultat:

0, 1, 2, 3, 4, 5, …

Les variables statiques de C ont la durée de vie du programme.

Si elles sont définies dans une fonction, elles ont une scope locale, c’est-à-dire qu’elles ne sont accessibles que dans ces fonctions. La valeur des variables statiques est préservée entre les appels de fonction.

Par exemple:

 void function() { static int var = 1; var++; printf("%d", var); } int main() { function(); // Call 1 function(); // Call 2 } 

Dans le programme ci-dessus, var est stocké dans le segment de données. Sa durée de vie est l’ensemble du programme C.

Après l’appel de la fonction 1, var devient 2. Après l’appel de la fonction 2, var devient 3.

La valeur de var n’est pas détruite entre les appels de fonctions.

Si var avait entre une variable non statique et une variable locale, elle serait stockée dans le segment de stack du programme C. Puisque le frame de stack de la fonction est détruit après le retour de la fonction, la valeur de var est également détruite.

Les variables statiques initialisées sont stockées dans le segment de données du programme C, tandis que celles non initialisées sont stockées dans le segment BSS.

Une autre information sur static: Si une variable est globale et statique, elle a la durée de vie du programme C, mais elle a une scope de fichier. Il est visible uniquement dans ce fichier.

Pour essayer ceci:

fichier1.c

 static int x; int main() { printf("Accessing in same file%d", x): } 

fichier2.c

  extern int x; func() { printf("accessing in different file %d",x); // Not allowed, x has the file scope of file1.c } run gcc -c file1.c gcc -c file2.c 

Maintenant, essayez de les relier en utilisant:

 gcc -o output file1.o file2.o 

Cela donnerait une erreur de l’éditeur de liens car x a la scope du fichier file.c et l’éditeur de liens ne serait pas capable de résoudre la référence à la variable x utilisée dans fichier2.c.

Les références:

  1. http://en.wikipedia.org/wiki/Translation_unit_(programming)
  2. http://en.wikipedia.org/wiki/Call_stack

Une valeur de variable statique persiste entre différents appels de fonction et sa scope est limitée au bloc local. Une variable statique est toujours initialisée avec la valeur 0

Il y a 2 cas:

(1) Variables locales déclarées static : allouées dans le segment de données au lieu de la stack. Sa valeur est conservée lorsque vous appelez à nouveau la fonction.

(2) Variables globales ou fonctions déclarées static : Invisible en dehors de l’unité de compilation (c.-à-d. Sont des symboles locaux dans la table des symboles lors de la liaison).