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)?
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)?
Réponses:
(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();
}
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
Cela est utile dans les cas où une fonction doit conserver un état entre les invocations et où vous ne souhaitez pas utiliser de variables globales. Attention cependant, cette fonctionnalité doit être utilisée avec parcimonie - elle rend votre code non thread-safe 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 expose généralement seulement quelques fonctions "publiques" aux utilisateurs. Le reste de ses fonctions doit être créé static
, afin que l'utilisateur ne puisse pas y accéder. Il s'agit d'encapsulation, une bonne pratique.
Citant 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 conteneur. Dans les variables locales, statique 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 la mise en œuvre 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 au moment de la compilation, tandis que la mémoire allouée automatiquement est normalement implémentée comme une pile d'appels transitoires.
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 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.
.c
et de plusieurs fichiers d'en-tête, mais le diable est toujours dans ce qui n'est pas typique.
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 passés à cette fonction doivent être un tableau de type char
contenant au moins 10 éléments. Pour plus d'informations voir ma question ici .
arg[0]
jusqu'à arg[9]
avoir des valeurs ( ce qui implique également que la fonction n'accepte pas un pointeur NULL). Les compilateurs pourraient utiliser ces informations d'une manière ou d'une autre pour l'optimisation, et les analyseurs statiques peuvent utiliser ces informations pour s'assurer que la fonction ne reçoit jamais de pointeur nul (ou, si elle peut le dire, un tableau avec moins d'éléments que spécifié).
static
dans C99. Il a plus de dix ans et demi, mais tous les auteurs de compilateurs n'ont pas embrassé toutes les fonctionnalités de C99 - donc C99 dans son ensemble reste largement inconnu.
int arr[n];
, alors c'est un VLA (tableau de longueur variable) , qui a été ajouté en C99. C'est ce que vous vouliez dire?
Réponse courte ... cela dépend.
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 limitées à 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.
private
en ait pas en C, votre analogie est bonne: statique rend les choses "privées" à un fichier donné. Et les fichiers en C sont souvent mappés aux classes en C ++.
Exemple de portée variable multi-fichiers
Ici, j'illustre comment statique affecte la portée des définitions de fonction sur plusieurs fichiers.
ac
#include <stdio.h>
/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
/programming/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;
}
Compiler et exécuter:
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
Production:
m()
i = 1
si = 1
m()
i = 2
si = 2
a()
i = 3
si = 1
a()
i = 4
si = 2
Interprétation
si
, une pour chaque fichieri
Comme d'habitude, plus la portée est petite, mieux c'est, donc toujours déclarer des variables static
si vous le pouvez.
En programmation C, les fichiers sont souvent utilisés pour représenter des "classes", et static
variables représentent des membres statiques privés de la classe.
Ce que les normes en disent
C99 N1256 draft 6.7.1 "Storage-class specifiers" dit questatic
s'agit d'un "stockage-class specifier".
6.2.2 / 3 "Liens d'identifiants" dit static
impliqueinternal linkage
:
Si la déclaration d'un identificateur de portée de fichier pour un objet ou une fonction contient le spécificateur de classe de stockage statique, l'identificateur a une liaison interne.
et 6.2.2 / 2 dit que internal linkage
se comporte comme dans notre exemple:
Dans l'ensemble d'unités de traduction et de bibliothèques qui constitue un programme entier, chaque déclaration d'un identifiant particulier avec liaison externe désigne le même objet ou la même fonction. Au sein d'une unité de traduction, chaque déclaration d'un identifiant avec lien interne dénote le même objet ou fonction.
où "unité de traduction est un fichier source après le prétraitement.
Comment GCC l'implémente-t-il pour ELF (Linux)?
Avec le STB_LOCAL
reliure.
Si nous compilons:
int i = 0;
static int si = 0;
et démontez 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 le.bss
section, nous nous attendons donc à 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 :
STB_LOCAL Les symboles locaux ne sont pas visibles en dehors du fichier objet contenant leur définition. Des 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 l'éditeur de liens combine plusieurs fichiers d'objets déplaçables, il n'autorise pas plusieurs définitions de symboles STB_GLOBAL avec le même nom.
ce qui est cohérent avec les erreurs de liaison sur plusieurs définitions non statiques.
Si nous augmentons l'optimisation avec -O3
, le si
symbole est entièrement supprimé de la table des symboles: il ne peut en aucun cas être utilisé de l'extérieur. 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 quelque chose? Peut-être pour le débogage.
Voir également
static
fonctions: https://stackoverflow.com/a/30319812/895245static
avec extern
, ce qui fait "le contraire": Comment utiliser extern pour partager des variables entre des fichiers source?Espaces de noms anonymes C ++
En C ++, vous souhaiterez peut-être utiliser des espaces de noms anonymes au lieu de statiques, ce qui produit un effet similaire, mais masque en outre les définitions de type: espaces de noms sans nom / anonymes vs fonctions statiques
Ça dépend:
int foo()
{
static int x;
return ++x;
}
La fonction retournerait 1, 2, 3, etc. --- la variable n'est pas sur la pile.
static int foo()
{
}
Cela signifie que cette fonction n'a de portée que dans ce fichier. Donc, ac et bc peuvent avoir des foo()
s différents , et foo n'est pas exposé aux objets partagés. Donc, si vous avez défini foo en ac, 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 "publiques" ne le sont pas.
Les gens continuent à dire que «statique» en C a deux significations. Je propose une autre façon de le voir qui lui donne un sens unique:
La raison pour laquelle il semble avoir deux significations est que, en C, chaque élément auquel «statique» peut être appliqué possède déjà l'une de ces deux propriétés , il semble donc que cet usage particulier n'implique 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), donc appliquer 'statique' 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 (fonction) actuelle, donc l'application de «statique» ne peut que les rendre persistantes.
Appliquer «statique» aux fonctions revient à l'appliquer aux variables globales - le code est nécessairement persistant (au moins dans le langage), donc 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 au mot-clé une signification différente. De même pour l'extension d'argument tableau C99.
static
donne un lien interne à un identifiant.
De Wikipédia:
Dans le langage de programmation C, statique est utilisé avec des variables et des fonctions globales pour définir leur portée sur le fichier conteneur. Dans les variables locales, statique 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 la mise en œuvre 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 au moment de la compilation, tandis que la mémoire allouée automatiquement est normalement implémentée comme une pile d'appels transitoires.
static
signifie des choses différentes dans des contextes différents.
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 une globale dans la mesure où elle n'est initialisée qu'une seule fois et conserve sa valeur. Dans cet exemple, chaque fois que vous appelez foo()
, un nombre croissant sera imprimé. 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 statique 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 de celui .obj
généré par le fichier. par exemple
static void foo() { ... }
Si vous déclarez une variable dans une fonction statique, sa valeur ne sera pas stockée dans la pile d'appels de fonction et sera toujours disponible lorsque vous appellerez à nouveau la fonction.
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.
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:
static
mot - clé (grand accent mis sur son utilisation dans le code en tant que mot-clé) est utilisé avec une déclaration, il donne à cet objet un lien 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 de toute façon visible que dans cette fonction). L'opposé de statique est le extern
mot - clé, qui donne un lien externe à un objet.Peter Van Der Linden donne ces deux significations dans "Expert C Programming":
register
un spécificateur de classe de stockage (C99 6.7.1 Spécificateurs de classe de stockage). Et c'est plus qu'un simple indice, par exemple, vous ne pouvez pas appliquer l'opérateur address-of &
sur un objet avec une classe de stockage, register
que le compilateur alloue ou non un registre.
En C, statique a deux significations, selon l'étendue 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 appel ultérieur de la procédure. si «i» était imprimé, il produirait une séquence de 0, 1, 2, 3, ...
Il est important de noter que les variables statiques dans les fonctions sont initialisées à la première entrée dans cette fonction et persistent même après la fin de leur appel; en cas de fonctions récursives, la variable statique n'est initialisée qu'une seule fois et persiste également pendant 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 la variable que dans le fichier source, la variable a été déclarée.
Si vous le déclarez dans un mytest.c
fichier:
static int my_variable;
Cette variable n'est alors visible que depuis ce fichier. La variable ne peut pas être exportée ailleurs.
Si vous déclarez à l'intérieur d'une fonction, la valeur de la variable gardera sa valeur à chaque appel de la fonction.
Une fonction statique ne peut pas être exportée de l'extérieur du fichier. Donc dans un *.c
fichier, vous cachez les fonctions et les variables si vous les déclarez statiques.
Les variables statiques en C ont la durée de vie du programme.
S'ils sont définis dans une fonction, ils ont une portée locale, c'est-à-dire qu'ils ne sont accessibles qu'à l'intérieur de 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 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.
S'il y var
avait entre une variable non statique et locale, il serait stocké dans le segment de pile dans le programme C. Étant donné que 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 celles non initialisées sont stockées dans le segment BSS.
Une autre information sur statique: 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 n'est visible que dans ce fichier.
Pour essayer ceci:
static int x;
int main()
{
printf("Accessing in same file%d", x):
}
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 de l'éditeur de liens car x a la portée de fichier de file1.c et l'éditeur de liens ne pourrait pas résoudre la référence à la variable x utilisée dans file2.c.
Références:
static int var = 1;
changez-vous pas la valeur à un à chaque fois
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, ...
printf("%d, ", count); count++;
par `printf ("% d, ", count ++) (pas important: P).
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
: unité de compilation extérieure invisible (c'est-à-dire sont des symboles locaux dans la table des symboles lors de la liaison).
Les variables statiques ont la propriété de conserver leur valeur même lorsqu'elles sont hors de leur portée! Par conséquent, les variables statiques conservent leur valeur précédente dans leur étendue précédente et ne sont pas initialisées à nouveau dans la nouvelle étendue.
Regardez ceci par exemple - Une variable int statique reste en mémoire pendant l'exécution du programme. Une variable normale ou automatique est détruite lorsqu'un appel de fonction où la variable a été déclarée est terminé.
#include<stdio.h>
int fun()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
Cela produira: 1 2
Comme 1 reste dans la mémoire car il a été déclaré statique
Les variables statiques (comme les variables globales) sont initialisées à 0 si elles ne sont pas initialisées explicitement. Par exemple, dans le programme ci-dessous, la valeur de x est imprimée comme 0, tandis que la valeur de y est quelque chose d'ordure. Voir ceci pour plus de détails.
#include <stdio.h>
int main()
{
static int x;
int y;
printf("%d \n %d", x, y);
}
Cela produira: 0 [some_garbage_value]
Ce sont les principaux que j'ai trouvés qui n'ont pas été expliqués ci-dessus pour un débutant!
Dans la programmation C, static
est un mot-clé réservé qui contrôle à la fois la durée de vie et la visibilité. Si nous déclarons une variable statique dans une fonction, elle ne sera visible que dans cette fonction. Dans cette utilisation, la durée de vie de cette variable statique commencera lors d'un appel de fonction et sera détruite après l'exécution de cette fonction. vous pouvez voir l'exemple suivant:
#include<stdio.h>
int counterFunction()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("First Counter Output = %d\n", counterFunction());
printf("Second Counter Output = %d ", counterFunction());
return 0;
}
Le programme ci-dessus nous donnera ce résultat:
First Counter Output = 1
Second Counter Output = 1
Parce que dès que nous appelons la fonction, elle initialise le count = 0
. Et pendant que nous l'exécutons, counterFunction
il détruira la variable de comptage.