Avez-vous essayé de saisir ceci et de voir par vous-même?
wilhelmtell
21
Je veux comprendre pourquoi.
Vadiklk
7
@Vadiklk alors posez une question commençant par "Pourquoi"
Andrey
1
ideone.com/t9Bbe À quoi vous attendriez-vous? Le résultat ne correspond-il pas à vos attentes? Pourquoi vous attendiez-vous à votre résultat?
eckes le
Réponses:
187
Il y a deux problèmes ici, la durée de vie et la portée.
La portée de la variable est l'endroit où le nom de la variable peut être vu. Ici, x n'est visible que dans la fonction foo ().
La durée de vie d'une variable est la période sur laquelle elle existe. Si x était défini sans le mot-clé static, la durée de vie serait de l'entrée dans foo () au retour de foo (); il serait donc réinitialisé à 5 à chaque appel.
Le mot-clé static agit pour étendre la durée de vie d'une variable à la durée de vie du programme; par exemple, l'initialisation se produit une seule fois et une seule fois, puis la variable conserve sa valeur - quelle qu'elle soit - sur tous les futurs appels à foo ().
dans quels scénarios nous devons déclarer une variable comme statique à l'intérieur d'une fonction ?, juste curieux de savoir car je ne l'ai jamais utilisé auparavant?
Akay
Je dirais merci, mais tout cela a été répondu tout en haut de la page. ça me fait rire que les gens ne se contentent pas d'exécuter leur propre code. xD
Puddle
Cette réponse est fausse. Au moment où vous pensez aux fonctions récursives, les définitions décrites ici n'expliquent pas le comportement!
Philip Couling
53
Sortie : 6 7
Raison : la variable statique n'est initialisée qu'une seule fois (contrairement à la variable automatique) et une définition plus poussée de la variable statique serait contournée pendant l'exécution. Et s'il n'est pas initialisé manuellement, il est automatiquement initialisé par la valeur 0. Alors,
void foo(){staticint x =5;// assigns value of 5 only once
x++;
printf("%d", x);}int main(){
foo();// x = 6
foo();// x = 7return0;}
C'est la même chose que d'avoir le programme suivant:
staticint x =5;void foo(){
x++;
printf("%d", x);}int main(){
foo();
foo();return0;}
Tout ce que fait le mot-clé static dans ce programme, c'est qu'il dit au compilateur (essentiellement) "hé, j'ai une variable ici à laquelle je ne veux pas que quelqu'un d'autre accède, ne dis à personne d'autre qu'elle existe".
Dans une méthode, le mot-clé static dit au compilateur la même chose que ci-dessus, mais aussi, «ne dites à personne que cela existe en dehors de cette fonction, il ne devrait être accessible qu'à l'intérieur de cette fonction».
Eh bien, ce n'est pas la même chose. Il y a toujours le problème de la portée sur X. Dans cet exemple, vous pouvez poke and futz with xin main; c'est mondial. Dans l'exemple d'origine, il xétait local à foo, visible uniquement à l'intérieur de ce bloc, ce qui est généralement préférable: si foo existe pour être maintenu xde manière prévisible et visible, alors laisser les autres le pousser est généralement dangereux. Comme autre avantage de le garder dans la portée, foo() il reste également foo()portable.
user2149140
2
@ user2149140 'ne dites à personne que cela existe en dehors de cette fonction, il ne devrait être accessible qu'à l'intérieur de cette fonction'
DCShannon
3
Bien que vous ayez résolu le problème de la portée en raison de l'endroit où la variable est déclarée, la description de statique comme affectant la portée, plutôt que la durée de vie, semble incorrecte.
DCShannon
1
@Chameleon La question est étiquetée comme c, donc dans ce contexte, votre exemple serait illégal à l'échelle mondiale. (C nécessite des initialiseurs constants pour les globaux, C ++ ne le fait pas).
Richard J.Ross III
5
Une variable statique à l'intérieur d'une fonction a une durée de vie tant que votre programme s'exécute. Elle ne sera pas allouée à chaque fois que votre fonction est appelée et désallouée au retour de votre fonction.
Dire cela est comme une variable "globale" et dire SAUF que vous ne pouvez pas y accéder est un oxymore. Global signifie accessible partout. Ce qui dans ce cas d'une fonction statique à l'intérieur d'une fonction, il n'est PAS accessible partout. Le problème dans OP, comme d'autres l'ont noté, concerne la portée et la durée de vie. Veuillez ne pas confondre les gens avec l'utilisation du terme «global» et les induire en erreur sur la portée de la variable.
ChuckB
@ChuckB: C'est exact. Corrigé. Eh bien, ça fait 6 ans. Ma réponse précédente avait la perception d'il y a 6 ans!
Donotalo
5
Sortie: 6,7
Raison
La déclaration de xest à l'intérieur foomais l' x=5initialisation a lieu à l'extérieur de foo!
Ce que nous devons comprendre ici, c'est que
staticint x =5;
n'est pas la même chose que
staticint x;
x =5;
D'autres réponses ont utilisé les mots importants ici, portée et durée de vie, et ont souligné que la portée de xva du point de sa déclaration dans la fonction fooà la fin de la fonction foo. Par exemple, j'ai vérifié en déplaçant la déclaration à la fin de la fonction, et cela rend xnon déclaré à l' x++;instruction.
Ainsi, la partie static int x(portée) de l'instruction s'applique réellement là où vous la lisez, quelque part DANS la fonction et seulement à partir de là, pas au-dessus d'elle à l'intérieur de la fonction.
Cependant, la partie x = 5(durée de vie) de l'instruction est l' initialisation de la variable et se produit À L'EXTÉRIEUR de la fonction dans le cadre du chargement du programme. La variable xest née avec une valeur de 5quand le programme se charge.
J'ai lu ceci dans l'un des commentaires: " De plus, cela ne résout pas la partie vraiment déroutante, qui est le fait que l'initialiseur est ignoré lors des appels suivants. " Il est ignoré sur tous les appels. L'initialisation de la variable est en dehors du code de fonction proprement dit.
La valeur de 5 est théoriquement définie indépendamment du fait que foo soit appelé ou non, bien qu'un compilateur puisse optimiser la fonction si vous ne l'appelez nulle part. La valeur de 5 doit être dans la variable avant que foo ne soit appelé.
À l'intérieur de foo, il static int x = 5;est peu probable que l'instruction génère du code.
J'ai trouvé l'adresse xutilisée lorsque j'ai mis une fonction foodans un de mes programmes, puis j'ai (correctement) deviné que le même emplacement serait utilisé si je réexécutais le programme. La capture d'écran partielle ci-dessous montre qu'elle xa la valeur 5même avant le premier appel à foo.
La sortie sera 6 7. Une variable statique (qu'elle soit à l'intérieur d'une fonction ou non) est initialisée exactement une fois, avant l'exécution d'une fonction de cette unité de traduction. Après cela, il conserve sa valeur jusqu'à ce qu'il soit modifié.
Êtes-vous sûr que le statique est initialisé avant l'appel de la fonction et non lors du premier appel de la fonction?
Jesse Pepper
@JessePepper: Au moins si la mémoire est bonne, cela dépend si vous parlez de C ++ 98/03 ou C ++ 11. En C ++ 98/03, je crois que c'est comme décrit ci-dessus. En C ++ 11, le threading rend cela pratiquement impossible à faire, donc l'initialisation est effectuée lors de la première entrée dans la fonction.
Jerry Coffin
2
Je pense que vous vous trompez en fait. Je pense que même avant C ++ 11, il n'a été initialisé que lorsque la fonction est appelée. Ceci est important pour une solution commune au problème de dépendance d'initialisation statique.
Jesse Pepper
2
Vadiklk,
Pourquoi ...? La raison en est que la variable statique n'est initialisée qu'une seule fois et conserve sa valeur tout au long du programme. signifie que vous pouvez utiliser une variable statique entre les appels de fonction. il peut également être utilisé pour compter "combien de fois une fonction est appelée"
main(){staticint var =5;
printf("%d ",var--);if(var)
main();}
et la réponse est 5 4 3 2 1 et non 5 5 5 5 5 5 .... (boucle infinie) comme vous vous y attendez. encore une fois, la raison est que la variable statique est initialisée une fois, lors du prochain appel de main (), elle ne sera pas initialisée à 5 car elle est déjà initialisée dans le programme. Nous pouvons donc changer la valeur mais ne pouvons pas la réinitialiser. Voilà comment fonctionne la variable statique.
ou vous pouvez considérer comme par stockage: les variables statiques sont stockées sur la section de données d'un programme et les variables qui sont stockées dans la section de données sont initialisées une fois. et avant l'initialisation, ils sont conservés dans la section BSS.
À leur tour, les variables automatiques (locales) sont stockées sur la pile et toutes les variables de la pile sont réinitialisées à tout moment lorsque la fonction est appelée en tant que nouveau FAR (enregistrement d'activation de fonction) est créé pour cela.
ok pour plus de compréhension, faites l'exemple ci-dessus sans "statique" et faites-vous savoir quelle sera la sortie. Cela vous fait comprendre la différence entre les deux.
Variables locales statiques: les variables déclarées comme statiques à l'intérieur d'une fonction sont allouées statiquement tout en ayant la même portée que les variables locales automatiques. Par conséquent, toutes les valeurs que la fonction met dans ses variables locales statiques lors d'un appel seront toujours présentes lorsque la fonction est appelée à nouveau.
C'est terrible! "les variables déclarées statiques à l'intérieur d'une fonction sont allouées statiquement" - cela n'explique rien, sauf si vous savez déjà ce que cela signifie!
@Blank: eh bien, c'est ce à quoi je pensais que la deuxième phrase était destinée. Bien que je suppose que vous avez raison, cela devrait être mieux formulé.
Andrew White
De plus, cela ne résout pas la partie vraiment déroutante, qui est le fait que l'initialiseur est ignoré lors des appels suivants.
Tom Auger
alloué statiquement signifie pas de pile, ni de tas.
Chameleon
1
Vous obtiendrez 6 7 imprimés comme, comme cela est facilement testé, et voici la raison: Quand foo son premier appel, la variable statique x est initialisée à 5. Ensuite, elle est incrémentée à 6 et imprimée.
Passons maintenant au prochain appel à foo. Le programme ignore l'initialisation de la variable statique et utilise à la place la valeur 6 qui a été affectée à x la dernière fois. L'exécution se déroule normalement, vous donnant la valeur 7.
x est une variable globale qui n'est visible que depuis foo (). 5 est sa valeur initiale, telle qu'elle est stockée dans la section .data du code. Toute modification ultérieure écrase la valeur précédente. Il n'y a pas de code d'affectation généré dans le corps de la fonction.
6 et 7 Parce que la variable statique ne s'initialise qu'une seule fois, Donc 5 ++ devient 6 au 1er appel 6 ++ devient 7 au 2ème appel Remarque - lorsque le 2ème appel se produit, la valeur x est 6 au lieu de 5 car x est une variable statique.
En C ++ 11 au moins, lorsque l'expression utilisée pour initialiser une variable statique locale n'est pas une 'constexpr' (ne peut pas être évaluée par le compilateur), l'initialisation doit se produire lors du premier appel à la fonction. L'exemple le plus simple consiste à utiliser directement un paramètre pour initialiser la variable statique locale. Ainsi, le compilateur doit émettre du code pour deviner si l'appel est le premier ou non, ce qui à son tour nécessite une variable booléenne locale. J'ai compilé un tel exemple et vérifié que cela est vrai en voyant le code d'assemblage. L'exemple peut être comme ceci:
void f(int p ){staticconstint first_p = p ;
cout <<"first p == "<< p << endl ;}void main(){
f(1); f(2); f(3);}
bien sûr, lorsque l'expression est 'constexpr', cela n'est pas obligatoire et la variable peut être initialisée au chargement du programme en utilisant une valeur stockée par le compilateur dans le code d'assemblage de sortie.
Réponses:
Il y a deux problèmes ici, la durée de vie et la portée.
La portée de la variable est l'endroit où le nom de la variable peut être vu. Ici, x n'est visible que dans la fonction foo ().
La durée de vie d'une variable est la période sur laquelle elle existe. Si x était défini sans le mot-clé static, la durée de vie serait de l'entrée dans foo () au retour de foo (); il serait donc réinitialisé à 5 à chaque appel.
Le mot-clé static agit pour étendre la durée de vie d'une variable à la durée de vie du programme; par exemple, l'initialisation se produit une seule fois et une seule fois, puis la variable conserve sa valeur - quelle qu'elle soit - sur tous les futurs appels à foo ().
la source
Sortie : 6 7
Raison : la variable statique n'est initialisée qu'une seule fois (contrairement à la variable automatique) et une définition plus poussée de la variable statique serait contournée pendant l'exécution. Et s'il n'est pas initialisé manuellement, il est automatiquement initialisé par la valeur 0. Alors,
la source
6 7
le compilateur fait en sorte que l'initialisation de la variable statique ne se produise pas à chaque fois que la fonction est entrée
la source
C'est la même chose que d'avoir le programme suivant:
Tout ce que fait le mot-clé static dans ce programme, c'est qu'il dit au compilateur (essentiellement) "hé, j'ai une variable ici à laquelle je ne veux pas que quelqu'un d'autre accède, ne dis à personne d'autre qu'elle existe".
Dans une méthode, le mot-clé static dit au compilateur la même chose que ci-dessus, mais aussi, «ne dites à personne que cela existe en dehors de cette fonction, il ne devrait être accessible qu'à l'intérieur de cette fonction».
J'espère que ça aide
la source
x
in main; c'est mondial. Dans l'exemple d'origine, ilx
était local à foo, visible uniquement à l'intérieur de ce bloc, ce qui est généralement préférable: si foo existe pour être maintenux
de manière prévisible et visible, alors laisser les autres le pousser est généralement dangereux. Comme autre avantage de le garder dans la portée,foo()
il reste égalementfoo()
portable.c
, donc dans ce contexte, votre exemple serait illégal à l'échelle mondiale. (C nécessite des initialiseurs constants pour les globaux, C ++ ne le fait pas).Une variable statique à l'intérieur d'une fonction a une durée de vie tant que votre programme s'exécute. Elle ne sera pas allouée à chaque fois que votre fonction est appelée et désallouée au retour de votre fonction.
la source
Sortie: 6,7
Raison
La déclaration de
x
est à l'intérieurfoo
mais l'x=5
initialisation a lieu à l'extérieur defoo
!Ce que nous devons comprendre ici, c'est que
n'est pas la même chose que
D'autres réponses ont utilisé les mots importants ici, portée et durée de vie, et ont souligné que la portée de
x
va du point de sa déclaration dans la fonctionfoo
à la fin de la fonctionfoo
. Par exemple, j'ai vérifié en déplaçant la déclaration à la fin de la fonction, et cela rendx
non déclaré à l'x++;
instruction.Ainsi, la partie
static int x
(portée) de l'instruction s'applique réellement là où vous la lisez, quelque part DANS la fonction et seulement à partir de là, pas au-dessus d'elle à l'intérieur de la fonction.Cependant, la partie
x = 5
(durée de vie) de l'instruction est l' initialisation de la variable et se produit À L'EXTÉRIEUR de la fonction dans le cadre du chargement du programme. La variablex
est née avec une valeur de5
quand le programme se charge.J'ai lu ceci dans l'un des commentaires: " De plus, cela ne résout pas la partie vraiment déroutante, qui est le fait que l'initialiseur est ignoré lors des appels suivants. " Il est ignoré sur tous les appels. L'initialisation de la variable est en dehors du code de fonction proprement dit.
La valeur de 5 est théoriquement définie indépendamment du fait que foo soit appelé ou non, bien qu'un compilateur puisse optimiser la fonction si vous ne l'appelez nulle part. La valeur de 5 doit être dans la variable avant que foo ne soit appelé.
À l'intérieur de
foo
, ilstatic int x = 5;
est peu probable que l'instruction génère du code.J'ai trouvé l'adresse
x
utilisée lorsque j'ai mis une fonctionfoo
dans un de mes programmes, puis j'ai (correctement) deviné que le même emplacement serait utilisé si je réexécutais le programme. La capture d'écran partielle ci-dessous montre qu'ellex
a la valeur5
même avant le premier appel àfoo
.la source
La sortie sera
6 7
. Une variable statique (qu'elle soit à l'intérieur d'une fonction ou non) est initialisée exactement une fois, avant l'exécution d'une fonction de cette unité de traduction. Après cela, il conserve sa valeur jusqu'à ce qu'il soit modifié.la source
Vadiklk,
Pourquoi ...? La raison en est que la variable statique n'est initialisée qu'une seule fois et conserve sa valeur tout au long du programme. signifie que vous pouvez utiliser une variable statique entre les appels de fonction. il peut également être utilisé pour compter "combien de fois une fonction est appelée"
et la réponse est 5 4 3 2 1 et non 5 5 5 5 5 5 .... (boucle infinie) comme vous vous y attendez. encore une fois, la raison est que la variable statique est initialisée une fois, lors du prochain appel de main (), elle ne sera pas initialisée à 5 car elle est déjà initialisée dans le programme. Nous pouvons donc changer la valeur mais ne pouvons pas la réinitialiser. Voilà comment fonctionne la variable statique.
ou vous pouvez considérer comme par stockage: les variables statiques sont stockées sur la section de données d'un programme et les variables qui sont stockées dans la section de données sont initialisées une fois. et avant l'initialisation, ils sont conservés dans la section BSS.
À leur tour, les variables automatiques (locales) sont stockées sur la pile et toutes les variables de la pile sont réinitialisées à tout moment lorsque la fonction est appelée en tant que nouveau FAR (enregistrement d'activation de fonction) est créé pour cela.
ok pour plus de compréhension, faites l'exemple ci-dessus sans "statique" et faites-vous savoir quelle sera la sortie. Cela vous fait comprendre la différence entre les deux.
Merci Javed
la source
Lisons simplement l'article de Wikipedia sur les variables statiques ...
la source
Vous obtiendrez 6 7 imprimés comme, comme cela est facilement testé, et voici la raison: Quand
foo
son premier appel, la variable statique x est initialisée à 5. Ensuite, elle est incrémentée à 6 et imprimée.Passons maintenant au prochain appel à
foo
. Le programme ignore l'initialisation de la variable statique et utilise à la place la valeur 6 qui a été affectée à x la dernière fois. L'exécution se déroule normalement, vous donnant la valeur 7.la source
x est une variable globale qui n'est visible que depuis foo (). 5 est sa valeur initiale, telle qu'elle est stockée dans la section .data du code. Toute modification ultérieure écrase la valeur précédente. Il n'y a pas de code d'affectation généré dans le corps de la fonction.
la source
6 et 7 Parce que la variable statique ne s'initialise qu'une seule fois, Donc 5 ++ devient 6 au 1er appel 6 ++ devient 7 au 2ème appel Remarque - lorsque le 2ème appel se produit, la valeur x est 6 au lieu de 5 car x est une variable statique.
la source
En C ++ 11 au moins, lorsque l'expression utilisée pour initialiser une variable statique locale n'est pas une 'constexpr' (ne peut pas être évaluée par le compilateur), l'initialisation doit se produire lors du premier appel à la fonction. L'exemple le plus simple consiste à utiliser directement un paramètre pour initialiser la variable statique locale. Ainsi, le compilateur doit émettre du code pour deviner si l'appel est le premier ou non, ce qui à son tour nécessite une variable booléenne locale. J'ai compilé un tel exemple et vérifié que cela est vrai en voyant le code d'assemblage. L'exemple peut être comme ceci:
bien sûr, lorsque l'expression est 'constexpr', cela n'est pas obligatoire et la variable peut être initialisée au chargement du programme en utilisant une valeur stockée par le compilateur dans le code d'assemblage de sortie.
la source