Pour comprendre, il est utile de décomposer les opérations effectuées.
int * p; // déclaration d'un pointeur p
p = dix(); // assignation du pointeur p à la valeur retournée par la fonction dix()
Si tu as compris ce que retourne la fonction dix(), tu as la réponse à ta question. La question qui est intéressante pour comprendre la portée et la durée de vie des variables est : que vaut i à la fin du main ?
C'est surtout que vaut le i déclaré dans dix() lorsque dix() a fini de s'exécuter… et qu'on veut utiliser sa valeur via son adresse (retour de &i stocké dans p et utilisation de *p).
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
Note: pour cet exemple il aurait été plus propre de nommer différemment les variables locales entre les fonctions, car ce n'est pas un problème de portée de nom.
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
Que la variable dans dix() s'appelle truc ou machin ou i n'a pas d'impact sur le problème qui est un problème de durée de vie.
Le fait qu'il puisse y avoir différente variables i dans différentes fonctions, avec chacune une portée (visiblité) qui est celle de la fonction, est un peu différent.
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
Si, il l'est, le résultat sera "0" ou quoi que soit écrit dans la première variable (ici i) de la fonction zero.
- la ou les variables selon l'empreinte mémoire du type de celles -ci. -
C'est un exercice pour expliquer le fonctionnement de la pile du thread d'un processus.
Attention, il suffit d'activer les optimisations pour que ça ne fonctionne plus.
( les variables qui ne font rien vont disparaître et les fonctions aussi, du coup).
on ne sait pas ce qui sera à stocké à l'adresse où était la variable locale i.
Il s'agit de ce qui se trouve sous le pointeur de pile (stack pointer), donc de l'état de la dernière variable 'locale' (au type près) de la dernière fonction appelée.
Il s'agit de ce qui se trouve sous le pointeur de pile (stack pointer), donc de l'état de la dernière variable 'locale' (au type près) de la dernière fonction appelée.
Bof, moi la question que je me pose, c'est ce que dit la norme à ce sujet. Si elle ne dit rien, on a effectivement un comportement indéterminé. Les compilateurs implémente le comportement que tu décris, mais il n'est pas dit que tous soient tenus de le faire de la même façon. D'ailleurs, tu le dis toi-même, il semble que quand les optimisations sont activées, ça ne marche plus pareil.
Posté par David Marec .
Évalué à 2.
Dernière modification le 31 octobre 2019 à 13:29.
Bof, moi la question que je me pose, c'est ce que dit la norme à ce sujet.
Que l'on accède à une variable hors de sa portée, c'est un cas d' undefined behavior.
If an object is referred to outside of its lifetime, the behavior is undefined. §6.2.4/2
C'est pourquoi ce code n'est pas un exercice de langage C.
Je le considère comme un exercice pour expliquer le mécanisme des fonctions et de leurs piles, voire de l'espace mémoire utilisateur.C'est même un classique.
De mon point de vue, c'est la raison pour laquelle il est important de savoir pourquoi la valeur de i est malgré tout déterminée sur les architectures/OS les plus courantes.
Le fait est que le C et le C++ doivent être les seul langages (sans intégrer directement de l'assembleur) dans lequel on peut écrire et compiler de telles choses.
Si elle ne dit rien, on a effectivement un comportement indéterminé
Au contraire, c'est parce qu'elle le dit que c'en est un. Cela aurait pu être unspecified ou implementation-defined voire invalide.
D'ailleurs, tu le dis toi-même, il semble que quand les optimisations sont activées, ça ne marche plus pareil
C'est plus que ça.
Les compilateurs vont faire ce qu'ils veulent de ce code, même sans optimisation.
Ils peuvent le réduire à :
Posté par lolop (site web personnel) .
Évalué à 2.
Dernière modification le 30 octobre 2019 à 16:31.
Tu as un j local à dix() et un autrej local à zero(), la classification static de l'un n'a pas d'impact sur l'autre. Donc tu remets dans zero() le même problème que tu avais précédement dans dix(). Une variable locale statique n'est pas une variable globale.
De plus, tu déclares que zero() retourne un entier, mais tu lui fais retourner quoi ?
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
Posté par nico4nicolas .
Évalué à 2.
Dernière modification le 30 octobre 2019 à 16:41.
Ca fonctionne ! Que t'attendais-tu à avoir ?
Il faut faire la différence en durée de vie et portée des variables. En ajoutant le mot clé "static" à la variable i/j dans la fonction dix(), tu changes sa durée de vie mais pas sa portée. La variable n'est accessible que dans la fonction dix()… sauf à utiliser un pointeur.
Il faut garder à l'esprit que dans ton programme initial, tu avais 3 variables i différentes. Ajouter le mot clé static ne change pas la portée de ces variables et tu as toujours 3 variables i différentes (le changement de nom de i en j n'ayant absolument aucune importance).
Edit : pardon, ça ne fonctionne pas car tu utilises la fonction zero() comme la fonciton dix() était utilisée initialement, tu retombes donc sur le même problème. Et en plus, j n'est pas déclaré dans la fonction zero() donc ça ne doit même pas compiler.
Posté par nico4nicolas .
Évalué à 4.
Dernière modification le 30 octobre 2019 à 16:02.
C'est exactement ça ! Le comportement n'est pas prévisible, on ne sait pas ce qui sera à stocké à l'adresse où était la variable locale i. On ne sait pas si cette adresse sera accessible.
toto.c: In function ‘dix’:
toto.c:4:9: warning: function returns address of local variable [-Wreturn-local-addr]
return &i;
^~
Ta solution à base de static fonctionne pour corriger le problème de l'existence de la variable. Après il faut voir le sens qu'ont les fonctions, c'est au delà de l'exemple.
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
As-tu essayé de le compiler et de l'exécuter ?
ça devrait merder à la dernière ligne, car l'adresse pointée par p pointe sur une variable locale de la fonction "dix", et l'emplacement mémoire occupé par cette variable est libéré lorsqu'on sort de la fonction. C'est très mal de faire ça…
Pour la petite anecdote, j'ai eu ce genre de bug récemment, et je l'ai résolu en faisant pipi… :) :) :)
C'est sans doute un exercice pour comprendre la portée des variables non ?
# Décomposer les opérations
Posté par nico4nicolas . Évalué à 6.
Pour comprendre, il est utile de décomposer les opérations effectuées.
Si tu as compris ce que retourne la fonction dix(), tu as la réponse à ta question. La question qui est intéressante pour comprendre la portée et la durée de vie des variables est : que vaut i à la fin du main ?
[^] # Re: Décomposer les opérations
Posté par lolop (site web personnel) . Évalué à 3.
C'est surtout que vaut le
i
déclaré dansdix()
lorsquedix()
a fini de s'exécuter… et qu'on veut utiliser sa valeur via son adresse (retour de&i
stocké dansp
et utilisation de*p
).Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
[^] # Re: Décomposer les opérations
Posté par lolop (site web personnel) . Évalué à 2.
Note: pour cet exemple il aurait été plus propre de nommer différemment les variables locales entre les fonctions, car ce n'est pas un problème de portée de nom.
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
[^] # Re: Décomposer les opérations
Posté par lolop (site web personnel) . Évalué à 2.
Que la variable dans
dix()
s'appelletruc
oumachin
oui
n'a pas d'impact sur le problème qui est un problème de durée de vie.Le fait qu'il puisse y avoir différente variables
i
dans différentes fonctions, avec chacune une portée (visiblité) qui est celle de la fonction, est un peu différent.Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
[^] # Re: Décomposer les opérations
Posté par nico4nicolas . Évalué à 3.
Qu'est-ce qui ne fonctionne pas ? Avec ton code modifié, la valeur de i à la fin du programme est prévisible.
[^] # Re: Décomposer les opérations
Posté par max22 . Évalué à 2.
pourquoi dis-tu que ça ne marche pas ? j'ai essayé, on obtient i=10 à la fin ce qui me semble normal.
tu t'attendais à quoi ?
[^] # Re: Décomposer les opérations
Posté par David Marec . Évalué à 2.
Si, il l'est, le résultat sera "0" ou quoi que soit écrit dans la première variable (ici
i
) de la fonctionzero
.- la ou les variables selon l'empreinte mémoire du type de celles -ci. -
C'est un exercice pour expliquer le fonctionnement de la pile du thread d'un processus.
Attention, il suffit d'activer les optimisations pour que ça ne fonctionne plus.
( les variables qui ne font rien vont disparaître et les fonctions aussi, du coup).
Il s'agit de ce qui se trouve sous le pointeur de pile (stack pointer), donc de l'état de la dernière variable 'locale' (au type près) de la dernière fonction appelée.
Elle le sera.
[^] # Re: Décomposer les opérations
Posté par totof2000 . Évalué à 2.
Bof, moi la question que je me pose, c'est ce que dit la norme à ce sujet. Si elle ne dit rien, on a effectivement un comportement indéterminé. Les compilateurs implémente le comportement que tu décris, mais il n'est pas dit que tous soient tenus de le faire de la même façon. D'ailleurs, tu le dis toi-même, il semble que quand les optimisations sont activées, ça ne marche plus pareil.
[^] # Re: Décomposer les opérations
Posté par David Marec . Évalué à 2. Dernière modification le 31 octobre 2019 à 13:29.
Que l'on accède à une variable hors de sa portée, c'est un cas d' undefined behavior.
C'est pourquoi ce code n'est pas un exercice de langage C.
Je le considère comme un exercice pour expliquer le mécanisme des fonctions et de leurs piles, voire de l'espace mémoire utilisateur.C'est même un classique.
De mon point de vue, c'est la raison pour laquelle il est important de savoir pourquoi la valeur de
i
est malgré tout déterminée sur les architectures/OS les plus courantes.Le fait est que le C et le C++ doivent être les seul langages (sans intégrer directement de l'assembleur) dans lequel on peut écrire et compiler de telles choses.
Au contraire, c'est parce qu'elle le dit que c'en est un. Cela aurait pu être unspecified ou implementation-defined voire invalide.
C'est plus que ça.
Les compilateurs vont faire ce qu'ils veulent de ce code, même sans optimisation.
Ils peuvent le réduire à :
si ça leur chante.
Mais on sort du sujet de l’exercice, AMHA.
[^] # Re: Décomposer les opérations
Posté par lolop (site web personnel) . Évalué à 2. Dernière modification le 30 octobre 2019 à 16:31.
Tu as un
j
local àdix()
et un autrej
local àzero()
, la classificationstatic
de l'un n'a pas d'impact sur l'autre. Donc tu remets danszero()
le même problème que tu avais précédement dansdix()
. Une variable locale statique n'est pas une variable globale.De plus, tu déclares que
zero()
retourne un entier, mais tu lui fais retourner quoi ?Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
[^] # Re: Décomposer les opérations
Posté par nico4nicolas . Évalué à 2. Dernière modification le 30 octobre 2019 à 16:41.
Ca fonctionne ! Que t'attendais-tu à avoir ?
Il faut faire la différence en durée de vie et portée des variables. En ajoutant le mot clé "static" à la variable i/j dans la fonction dix(), tu changes sa durée de vie mais pas sa portée. La variable n'est accessible que dans la fonction dix()… sauf à utiliser un pointeur.
Il faut garder à l'esprit que dans ton programme initial, tu avais 3 variables i différentes. Ajouter le mot clé static ne change pas la portée de ces variables et tu as toujours 3 variables i différentes (le changement de nom de i en j n'ayant absolument aucune importance).
Edit : pardon, ça ne fonctionne pas car tu utilises la fonction zero() comme la fonciton dix() était utilisée initialement, tu retombes donc sur le même problème. Et en plus, j n'est pas déclaré dans la fonction zero() donc ça ne doit même pas compiler.
[^] # Re: Décomposer les opérations
Posté par David Marec . Évalué à 3.
qu'est ce qui "marche" selon vous ?
Non, il étend la portée de la variable au fichier qui la contient.
De fait, elle ne peut plus alors être allouée sur la pile.
[^] # Re: Décomposer les opérations
Posté par nico4nicolas . Évalué à 4. Dernière modification le 30 octobre 2019 à 16:02.
C'est exactement ça ! Le comportement n'est pas prévisible, on ne sait pas ce qui sera à stocké à l'adresse où était la variable locale i. On ne sait pas si cette adresse sera accessible.
[^] # Re: Décomposer les opérations
Posté par lolop (site web personnel) . Évalué à 3.
Oui. D'ailleurs gcc te préviens :
Ta solution à base de
static
fonctionne pour corriger le problème de l'existence de la variable. Après il faut voir le sens qu'ont les fonctions, c'est au delà de l'exemple.Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
# Compilation ?
Posté par max22 . Évalué à 1.
As-tu essayé de le compiler et de l'exécuter ?
ça devrait merder à la dernière ligne, car l'adresse pointée par p pointe sur une variable locale de la fonction "dix", et l'emplacement mémoire occupé par cette variable est libéré lorsqu'on sort de la fonction. C'est très mal de faire ça…
Pour la petite anecdote, j'ai eu ce genre de bug récemment, et je l'ai résolu en faisant pipi… :) :) :)
C'est sans doute un exercice pour comprendre la portée des variables non ?
# Re: merci
Posté par AncalagonTotof . Évalué à 0.
Hello,
J'ai pas lu tous les commentaires (trop dur au p'tit déj …).
Est-ce que quelqu'un a pensé à te dire d'arrêter de coder comme ça ?
Parce que ça te fatigue déjà.
Et pour les autres, tu te rends pas compte de ce que c'est. Ça nous fout une angoisse …
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.