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 objets)?
18 réponses
- Une variable statique à l'intérieur d'une fonction conserve sa valeur entre les appels.
- une variable globale statique ou une fonction n'est " vue " que 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 <stdio.h>
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();
}
Cette impression:
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 très parcimonieusement - cela rend votre code non sûr et plus difficile à comprendre.
(2) est largement utilisé comme fonction de" contrôle d'accès". Si vous avez un .fichier c implémentant certaines fonctionnalités, il n'expose généralement que quelques fonctions "publiques" aux utilisateurs. Le reste de ses fonctions doit être fait static
, de sorte que l'utilisateur ne puisse pas y accéder. C'est l'encapsulation, une bonne pratique.
, Citant Wikipedia:
Dans le langage de programmation C, statique est utilisé avec des variables globales et fonctions pour définir leur portée sur contenant le fichier. Dans les variables locales, statique est utilisé pour stocker la variable dans la mémoire allouée statiquement au lieu de l'allocation automatique mémoire. Alors que la langue ne le fait pas dictent la mise en œuvre de type de mémoire, alloué statiquement la mémoire est généralement réservée dans les données segment du programme à la compilation le temps, tandis que le automatiquement la mémoire allouée est normalement mis en œuvre en tant que une pile d'appels transitoires.
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, {[2] } est également utilisé pour définir des attributs de classe (partagés entre tous les objets de la même classe) et des méthodes. En C, il n'y a pas de classes, donc cette fonctionnalité n'est pas pertinente.
Il y a une autre utilisation non couverte ici, et 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 passés à 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.
Les variables locales définies statiques ne perdent pas leur valeur entre les appels de fonction. En d'autres termes, ce sont des variables globales, mais étendues à la fonction locale dans laquelle elles sont définies.
Les variables globales statiques ne sont pas visibles en dehors du fichier C dans lequel elles sont définies.
Les fonctions statiques ne sont pas visibles en dehors du fichier C dans lequel elles sont définies.
Exemple de portée variable multi-fichiers
A. c:
#include <stdio.h>
/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
https://stackoverflow.com/questions/27667277/why-does-borland-compile-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("");
}
Principal.c :
#include <stdio.h>
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 a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
Sortie:
m()
i = 1
si = 1
m()
i = 2
si = 2
a()
i = 3
si = 1
a()
i = 4
si = 2
L'Interprétation
- il y a deux variables distinctes pour
si
, un pour chaque fichier - , il existe une seule variable partagée pour
i
Comme d'habitude, plus la portée est petite, mieux c'est, donc déclarez toujours les variables static
Si vous pouvez.
En programmation C, les fichiers sont souvent utilisés pour représenter des "classes", et les variables static
représentent des membres statiques privés de la classe.
Ce que les normes disent à ce sujet
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 d'identifiants", dit - static
implique internal linkage
:
Si la déclaration d'un identifiant de portée de fichier pour un objet ou une fonction contient le spécificateur de classe de stockage statique, l'identifiant a une liaison 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 entier, chaque déclaration d'un identifiant particulier avec lien externe dénote le même objet ou la même fonction. Dans une unité de traduction, chaque déclaration d'un identifiant avec liaison interne indique le même objet ou la même fonction.
Où " translation unit est un fichier source après 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
, Donc la liaison est la seule différence significative entre eux. Value
est juste leur décalage dans la section .bss
, donc nous nous attendons à ce qu'il diffère.
STB_LOCAL
est documenté sur la spécification ELF à http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :
Les symboles locaux STB_LOCAL ne sont pas visibles en dehors du fichier objet 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 static
.
Les Variables sans statique sont STB_GLOBAL
, et la spécification dit:
Lorsque le lien editor combine plusieurs fichiers objet relocalisables, il n'autorise pas plusieurs définitions 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 pas être utilisé de l'extérieur de toute façon. TODO pourquoi garder les variables statiques sur la table des symboles quand il n'y a pas d'optimisation? Peuvent-ils être utilisés pour quoi que ce soit? Peut-être que pour le débogage.
Voir aussi
- analogue pour les fonctions
static
: https://stackoverflow.com/a/30319812/895245 - comparez
static
avecextern
, ce qui fait "le contraire": comment utiliser extern pour partager des variables entre les fichiers source?
Essayez-le vous-même
Exemple sur github pour vous de jouer avec.
Cela dépend:
int foo()
{
static int x;
return ++x;
}
La fonction retournerait 1, 2, 3, etc. --- la variable n'est pas sur la pile.
A. c:
static int foo()
{
}
Cela signifie que cette fonction n'a de portée que dans ce fichier. Ainsi, A. c et B. c peuvent avoir des foo()
s différents, et foo n'est pas exposé à des objets partagés. Donc, si vous avez défini foo dans A. c, vous ne pouvez pas y accéder depuis b.c
ou depuis d'autres endroits.
Dans la plupart des bibliothèques C, toutes les fonctions" privées "sont statiques et la plupart des fonctions" publiques " ne le sont pas.
Les gens continuent à dire que "statique" en C a deux significations. J'offre une autre façon de le voir qui lui donne une seule signification:
- L'application de 'static' à un élément force cet élément à avoir deux propriétés: (A) il n'est pas visible en dehors de la portée actuelle; (b) il est persistant.
La raison pour laquelle il semble avoir deux significations, c'est que, en C, chaque élément, pour qui "statique" peut être appliqué possède déjà l'une de ces deux propriétés, donc semble, comme si les l'utilisation particulière implique seulement l'autre.
Par exemple, considérez les variables. Les Variables déclarées en dehors des fonctions ont déjà de la persistance (dans le segment de données), donc l'application 'static' ne peut que les rendre non visibles en dehors de la portée actuelle (Unité de compilation). Au contraire, les variables déclarées à l'intérieur des fonctions ont déjà une non-visibilité en dehors de la portée actuelle (fonction), donc l'application 'statique' ne peut que les rendre persistantes.
Appliquer 'static' aux fonctions est juste comme l'appliquer aux variables globales-le code est nécessairement persistant (au moins dans le langage), donc seule la visibilité peut être modifiée.
NOTE: ces commentaires ne s'appliquent qu'à C. En C++, appliquer 'static' aux méthodes de classe donne vraiment au mot-clé une signification différente. De même pour l'extension C99 array-argument.
static
signifie différentes choses dans différents contextes.
-
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 en ce sens qu'elle n'est initialisée qu'une seule fois et qu'elle conserve sa valeur. Dans cet exemple, chaque fois que vous appelez
foo()
, il affichera un nombre croissant. La variable statique n'est initialisée qu'une seule fois.void foo () { static int i = 0; printf("%d", i); i++ }
-
Une autre utilisation de static est lorsque vous implémentez une fonction ou global variable dans une .C mais ne veulent pas que son symbole soit visible en dehors du
.obj
généré par le fichier. par exemplestatic void foo() { ... }
Wikipédia:
dans le langage de programmation C, static est utilisé avec des variables et des fonctions globales pour définir leur portée sur le fichier contenant. Dans les variables locales, static est utilisé pour stocker la variable dans la mémoire allouée statiquement au lieu de la mémoire allouée automatiquement. Bien que le langage ne dicte pas l'implémentation de l'un ou l'autre type de mémoire, la mémoire allouée statiquement est généralement réservée dans le segment de données du programme lors de la compilation temps, tandis que la mémoire automatiquement allouée est normalement implémentée comme une pile d'appels transitoires.
Je déteste répondre à une vieille question, mais je ne pense pas que quelqu'un ait mentionné comment K&R l'explique dans la section A4.1 de "le langage de programmation C".
En bref, le mot statique est utilisé avec deux significations:
- Static est l'une des deux classes de stockage (l'autre étant automatique). Un objet statique conserve sa valeur entre les appels. Les objets déclarés en dehors de tous les blocs sont toujours statiques et ne peuvent pas être rendus automatiques.
- , Mais, lorsque le
static
mot-clé (gros accent sur son utilisation dans code comme mot-clé) est utilisé avec une déclaration, il donne à cet objet une liaison interne de sorte qu'il ne peut être utilisé que dans cette unité de traduction. Mais si le mot-clé est utilisé dans une fonction, il change la classe de stockage de l'objet (l'objet ne serait visible que dans cette fonction de toute façon). Le contraire de static est le mot cléextern
, qui donne un lien externe d'objet.
Peter Van Der Linden donne ces deux significations dans " Expert C Programmation":
- 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 seront pas stockées sur la pile d'appel et sera toujours disponible lorsque vous appelez la fonction de nouveau.
Si vous déclarez une variable globale statique, sa portée sera limitée au sein du fichier dans lequel vous l'avez déclarée. Ceci est légèrement plus sûr qu'un global régulier qui peut être lu et modifié tout au long de votre programme.
En C, statique a deux significations, selon la portée de son utilisation. Dans la portée globale, lorsqu'un objet est déclaré au niveau du fichier, cela signifie que cet objet n'est visible que dans ce fichier.
À toute autre portée, il déclare un objet qui conservera sa valeur entre les différents moments où la portée particulière est entrée. Par exemple, si un int est supprimé 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é, il produirait une séquence de 0, 1, 2, 3,...
Si vous déclarez cela dans un mytest.fichier c:
static int my_variable;
Alors cette variable ne peut être vue qu'à partir de ce fichier. La variable ne peut être exportée nulle part ailleurs.
Si vous déclarez dans une fonction, la valeur de la variable conservera sa valeur chaque fois que la fonction est appelée.
Une fonction statique ne peut pas être exportée depuis l'extérieur du fichier. Ainsi, dans un *.fichier c, vous cachez les fonctions et les variables Si vous les déclarez statiques.
Il est important de noter que les variables statiques dans les 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
Si la variable a été créée en dehors d'une fonction, cela signifie que le programmeur ne peut utiliser la variable que dans le fichier source de la variable a été déclaré.
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, et il enregistre les données entre les appels, et il ne le 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();
}
}
La sortie:
0, 1, 2, 3, 4, 5, ...
Les variables statiques en C ont la durée de vie du programme.
Si elles sont définies dans une fonction, elles ont une portée locale, c'est-à-dire qu'elles ne sont accessibles qu'à l'intérieur de ces fonctions. La valeur des variables statiques est conservé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 fonction 1, var
devient 2. Après l'appel de fonction 2, var
devient 3.
La valeur de var
n'est pas détruite entre les appels de fonctions.
Si var
avait entre la variable non statique et la variable locale, elle serait stockée dans le segment de pile dans le programme C. Comme le cadre de pile 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 les variables non initialisées sont stockées dans le segment BSS.
Une autre information à propos de static: si une variable est globale et statique, elle a la durée de vie du programme C, mais elle a une portée 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
Essayez maintenant de les lier en utilisant:
gcc -o output file1.o file2.o
Cela donnerait une erreur d'éditeur de liens Car x a la portée du fichier de file1.c et l'éditeur de liens ne serait pas en mesure de résoudre la référence à la variable x utilisée dans fichier2.c.
Références:
Une valeur de variable statique persiste entre différents appels de fonction et sa portée est limitée au bloc local une var statique s'initialise toujours 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 pile. Sa valeur est conservée lorsque vous appelez à nouveau la fonction.
(2) variables ou fonctions globales déclarées static
: Invisible en dehors de l'Unité de compilation (c'est-à-dire sont des symboles locaux dans la table de symboles pendant la liaison).