Question 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)?


854
2018-02-21 06:47


origine


Réponses:


  1. Une variable statique à l'intérieur d'une fonction conserve sa valeur entre les invocations.
  2. 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();
}

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 que vous ne souhaitez pas utiliser de variables globales. Attention cependant, cette fonctionnalité doit être utilisée avec parcimonie - cela rend votre code non-thread-safe et plus difficile à comprendre.

(2) Est largement utilisé comme une fonctionnalité 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 devrait être fait static, de sorte que l'utilisateur ne sera pas en mesure d'y accéder. C'est l'encapsulation, une bonne pratique.

Citant Wikipédia:

Dans le langage de programmation C, statique   est utilisé avec des variables globales et   fonctions pour définir leur portée à la   contenant le fichier. Dans les variables locales,   static est utilisé pour stocker la variable   dans la mémoire allouée statiquement   au lieu de l'allocation automatique   Mémoire. Bien que la langue ne soit pas   dicter la mise en œuvre de soit   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   temps, tandis que le automatiquement   la mémoire allouée est normalement   implémenté comme une pile d'appel 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 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é est hors de propos.


1221
2018-02-21 06:51



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, ceci spécifie que les arguments passés à cette fonction doivent être un tableau de type char avec au moins 10 éléments dedans. Pour plus d'informations voir ma question ici.


188
2018-05-01 07:13



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 limitées à 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.


140
2018-02-21 06:56



Exemple de variable 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

Interprétation

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

Comme d'habitude, plus la portée est petite, mieux c'est, alors déclarez toujours des variables staticsi tu peux.

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

Ce que les normes en disent

Projet C99 N1256 6.7.1 "Spécificateurs de classe de stockage" dit que static est un "spécificateur de classe de stockage".

6.2.2 / 3 "Liaisons d'identifiants" dit static implique internal linkage:

Si la déclaration d'un identificateur d'étendue 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 des unités de traduction et des 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'identifiant avec lien interne désigne le même objet ou la même fonction.

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

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

Avec le STB_LOCAL contraignant.

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 le .bss section, 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:

STB_LOCAL Les symboles locaux 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_GLOBALet la spécification dit:

Lorsque l'éditeur de liens combine plusieurs fichiers objets relogeables, il n'autorise pas plusieurs définitions de symboles STB_GLOBAL ayant le même nom.

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

Si nous augmentons l'optimisation avec -O3, la si le 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 des 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

Essayez-le vous-même

Exemple sur github pour que tu joues avec.


45
2018-01-15 13:41



Ça dépend:

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

La fonction retournera 1, 2, 3, etc. --- la variable n'est pas dans la pile.

a.c:

static int foo()
{
}

Cela signifie que cette fonction n'a de portée que dans ce fichier. Donc, a.c et b.c peuvent avoir différents foo()s, et foo n'est pas exposé aux objets partagés. Donc, si vous avez défini foo dans a.c, vous ne pouviez pas y accéder depuis b.c ou de tout autre endroit.

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


32
2018-02-21 06:57



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

  • Appliquer 'static' à un item force cet item à avoir deux propriétés: (a) Il n'est pas visible en dehors de la portée courante; (b) Il est persistant.

La raison pour laquelle il semble avoir deux significations est que, en C, chaque élément auquel "statique" peut être appliqué a déjà l'une de ces deux propriétés, donc semble comme si cet usage particulier n'impliquait que l'autre.

Par exemple, considérons les variables. Les variables déclarées en dehors des fonctions ont déjà une persistance (dans le segment de données), l'application de 'static' ne peut donc les rendre visibles qu'en dehors de la portée actuelle (unité de compilation). Par contre, les variables déclarées à l'intérieur des fonctions ont déjà une non-visibilité en dehors de la portée (fonction) courante, donc appliquer 'static' ne peut que les rendre persistantes.

Appliquer 'static' aux fonctions revient à l'appliquer aux variables globales - le code est forcément persistant (au moins dans la langue), donc seule la visibilité peut être modifiée.

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


18
2018-04-27 13:47



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

  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 en ce sens qu'elle n'est initialisée qu'une seule fois et conserve sa valeur. Dans cet exemple, chaque fois que vous appelez foo() il imprimera 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() { ... }
    

12
2018-02-21 06:55



De Wikipedia:

Dans le langage de programmation C, statique est utilisé avec les variables globales et les fonctions pour définir leur portée dans le fichier conteneur. 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 au moment de la compilation, tandis que la mémoire allouée automatiquement est normalement implémentée comme pile d'appels transitoires.


11
2018-02-21 06:52