Valeur d'une variable locale non-initialisée

Le
Rémi Moyen
Bonjour,

En relisant un bout de code, je suis tombé sur une classe qui contient
un int comme membre, et bien que cette variable ne soit jamais
initialisée explicitement, elle a toujours la valeur 0 et le code
marche correctement. Ce que je ne comprends pas vraiment, je croyais
que les variables locales n'étaient pas initialisées à 0
automatiquement

Si je regarde mon Stroustrup, il me dit (4.9.5) que seules les
variables globales ou statiques locales sont initialisées à 0 par
défaut, et qu'une variable non-initialisée locale ou créée sur le t=
as
a une valeur non-définie. Les variables membres d'une classe, dans
quelle catégorie tombent-elles ? J'aurais dit le deuxième cas, non ?

Bon, je teste avec un petit code tout simple :
#include <iostream>
using namespace std;

int v1; //global, non static var
static int v2; //global, static var

void f() {
int v3; //local, non static
static int v4; //local, static
cout << "f(): " << v3 << " " << v4 << endl;
}

class A {
public:
void f() {cout << "A::f(): " << v5_ << " " << v6_ << endl;}
private:
int v5_; // class, non static
static int v6_; // class, static
};
int A::v6_;

int main() {
cout << "main(): " << v1 << " " << v2 << endl;
f();
A a;
a.f();
return 0;
}

Je compile avec :
g++ -ovariable -O1 -Wuninitialized main.cpp
main.cpp: In function `void f()':
main.cpp:12: warning: 'v3' might be used uninitialized in this
function

Et j'execute :
main(): 0 0
f(): 0 0
A::f(): 0 0

Donc clairement, toutes les variables ont été mises à 0. Pour v1 et
v2, c'est normal. v4 et v6_ aussi, elles sont statiques. Mais pour v3
et v5_ ? g++ m'informe bien pour v3, mais pourquoi ne m'informe-t-il
pas aussi pour v5_ ? Est-ce qu'elles sont à 0 par hasard (après tout,
une valeur "non-définie" par le standard peut très bien être 0) ? Est=
-
ce une particularité de g++ (v3.4.5, sur Linux RHEL 4.3) ? Est-ce
normal et j'ai mal compris le bouquin ?

Si quelqu'un pouvait m'expliquer, ça m'aiderait pas mal Merci
d'avance !
--
Rémi Moyen
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 3
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Jean-Marc Bourguet
Le #19705011
Rémi Moyen
Donc clairement, toutes les variables ont été mises à 0. Pour v1 et
v2, c'est normal. v4 et v6_ aussi, elles sont statiques. Mais pour v3
et v5_ ? g++ m'informe bien pour v3, mais pourquoi ne m'informe-t-il
pas aussi pour v5_ ? Est-ce qu'elles sont à 0 par hasard



Pas tout a fait par hasard (les OS initialisent toute la memoire a 0 avant
de la donner a un process), mais tu ne peux pas compter dessus. En
modifiant legerement ton programme (en faisant en sorte que la classe soit
allouee a un endroit ou on a deja ecrit d'autres valeurs et en faisant en
sorte que la pile soit de meme modifiee), j'arrive a d'autres valeurs.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Fabien LE LEZ
Le #19705001
On Mon, 6 Jul 2009 02:12:00 -0700 (PDT), Rémi Moyen

main(): 0 0
f(): 0 0
A::f(): 0 0



VC++ 2008 :
main(): 0 0
f(): 4331500 0
A::f(): 1 0

Donc clairement, toutes les variables ont été mises à 0.



Si le standard n'indique pas de valeur par défaut, l'implémentation
est libre d'assigner la valeur qu'elle veut. Ça peut être 0, ou la
suite d'octets qui se trouvait là en mémoire, ou 42.

Et même quand la norme indique que l'initialisation se fera, il me
semble qu'il vaut tout de même mieux l'expliciter si tu en as besoin.
Rémi Moyen
Le #19704991
On 6 juil, 10:21, Jean-Marc Bourguet
Rémi Moyen > Donc clairement, toutes les variables ont été mises à 0. Pour v1 et
> v2, c'est normal. v4 et v6_ aussi, elles sont statiques. Mais pour v3
> et v5_ ? g++ m'informe bien pour v3, mais pourquoi ne m'informe-t-il
> pas aussi pour v5_ ? Est-ce qu'elles sont à 0 par hasard

Pas tout a fait par hasard (les OS initialisent toute la memoire a 0 avan t
de la donner a un process), mais tu ne peux pas compter dessus.



D'accord. C'est à peu près ce que je soupçonnais, merci de confirmer.

Cependant, j'ai encore un doute avec le warning de g++ : pourquoi il
ne m'a pas prévenu pour A::v5_ ?

Est-ce que c'est parce qu'il n'arrive pas à tracer de manière fiable
tout le code et qu'au moment où j'appelle A::f(), il est trop
difficile pour lui de savoir si la variable a été initialisée ou non,
ou est-ce parce que quelque chose dans le langage garantit que la
variable est initialisée à 0 ?

 En
modifiant legerement ton programme (en faisant en sorte que la classe soi t
allouee a un endroit ou on a deja ecrit d'autres valeurs et en faisant en
sorte que la pile soit de meme modifiee), j'arrive a d'autres valeurs.



Par curiosité et parce que j'aimerais bien le faire moi-même, tu peux
me donner le programme modifié ?

Merci de ta réponse rapide !
--
Rémi Moyen
Rémi Moyen
Le #19705131
On 6 juil, 10:26, Fabien LE LEZ
[snip l'exemple, merci de confirmer que les 0 dans v3 et A::v5_ ne
sont pas imposés]

Si le standard n'indique pas de valeur par défaut, l'implémentation
est libre d'assigner la valeur qu'elle veut. Ça peut être 0, ou la
suite d'octets qui se trouvait là en mémoire, ou 42.

Et même quand la norme indique que l'initialisation se fera, il me
semble qu'il vaut tout de même mieux l'expliciter si tu en as besoin.



Je suis d'accord. Disons que je cherche essentiellement à comprendre
pourquoi le code fautif que j'ai trouvé marchait quand même (i.e.
pourquoi c'était toujours mis à 0). Je vois 3 raisons possibles :
1) le standard dit que ça doit être 0 (ta réponse et celle de Jean-
Marc excluent clairement cela, ce que je soupçonnais) ;
2) l'OS ou le compilateur mettent toujours systématiquement à 0, c'est
un choix d'implémentation (idem, c'est pas comme ça que ça marche) ;
3) dans mon cas particulier, un "coup de chance" (le fait que mon
programme de test est simpliste et utilise un bout de mémoire vierge,
par exemple) fait que l'OS a tout mis à 0 avant. Et c'est bien ça qui
se passe, je crois.

Vu que c'est dans du code que je maintiens, le cas 3 veut dire qu'il
faut impérativement que je passe du temps rapidement à vérifier si
cette erreur n'est pas faite ailleurs qu'à l'endroit où je l'ai vue
alors que les cas 1 et 2, j'aurais pu me permettre de ne les corriger
que quand je tombe dessus par hasard en cherchant autre chose, parce
que même si ça n'est pas du code très propre à mon goût, ça mar che
quand même comme attendu.

Merci pour ta réponse, je crois que j'ai toutes les infos
nécessaires !
--
Rémi Moyen
Jean-Marc Bourguet
Le #19705391
Rémi Moyen
On 6 juil, 10:21, Jean-Marc Bourguet > Rémi Moyen > > Donc clairement, toutes les variables ont été mises à 0. Pour v1 et
> > v2, c'est normal. v4 et v6_ aussi, elles sont statiques. Mais pour v3
> > et v5_ ? g++ m'informe bien pour v3, mais pourquoi ne m'informe-t-il
> > pas aussi pour v5_ ? Est-ce qu'elles sont à 0 par hasard
>
> Pas tout a fait par hasard (les OS initialisent toute la memoire a 0 avant
> de la donner a un process), mais tu ne peux pas compter dessus.

D'accord. C'est à peu près ce que je soupçonnais, merci de confirmer.

Cependant, j'ai encore un doute avec le warning de g++ : pourquoi il
ne m'a pas prévenu pour A::v5_ ?

Est-ce que c'est parce qu'il n'arrive pas à tracer de manière fiable
tout le code et qu'au moment où j'appelle A::f(), il est trop
difficile pour lui de savoir si la variable a été initialisée ou non,



Vraisemblablement quelque chose du genre.

ou est-ce parce que quelque chose dans le langage garantit que la
variable est initialisée à 0 ?

> En
> modifiant legerement ton programme (en faisant en sorte que la classe soit
> allouee a un endroit ou on a deja ecrit d'autres valeurs et en faisant en
> sorte que la pile soit de meme modifiee), j'arrive a d'autres valeurs.

Par curiosité et parce que j'aimerais bien le faire moi-même, tu peux
me donner le programme modifié ?



Voici (remarque l'ajout du dummy[1] qui a ete necessaire, j'ai pas ete voir
l'assembleur genere pour comprendre pourquoi).

#include <iostream>
using namespace std;

int v1; //global, non static var
static int v2; //global, static var

void f() {
int dummy[1];

int v3; //local, non static
static int v4; //local, static
cout << "f(): " << v3 << " " << v4 << endl;
}

class A {
public:
void f() {cout << "A::f(): " << v5_ << " " << v6_ << endl;}
private:
int v5_; // class, non static
static int v6_; // class, static
};
int A::v6_;

int mainRemy() {
cout << "main(): " << v1 << " " << v2 << endl;
f();
A a;
a.f();
return 0;
}

void g()
{
long init[] = { 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF };
}

int main() {
g();
return mainRemy();
}

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Michael Doubez
Le #19705511
On 6 juil, 11:12, Rémi Moyen
Bonjour,

En relisant un bout de code, je suis tombé sur une classe qui contient
un int comme membre, et bien que cette variable ne soit jamais
initialisée explicitement, elle a toujours la valeur 0 et le code
marche correctement. Ce que je ne comprends pas vraiment, je croyais
que les variables locales n'étaient pas initialisées à 0
automatiquement...


[snip]
Si quelqu'un pouvait m'expliquer, ça m'aiderait pas mal... Merci
d'avance !



As tu essayé avec divers degré d'optimisation ? Si je me souviens
bien, j'ai eu ce cas pour un programme qui marchait bien en mode debug
mais qui plantait en -02 à cause d'une variable non initialisée qui
prenait une valeur aléatoire.

--
Michael
Michel Decima
Le #19705491
Rémi Moyen a écrit :
On 6 juil, 10:26, Fabien LE LEZ
[snip l'exemple, merci de confirmer que les 0 dans v3 et A::v5_ ne
sont pas imposés]

Si le standard n'indique pas de valeur par défaut, l'implémentation
est libre d'assigner la valeur qu'elle veut. Ça peut être 0, ou la
suite d'octets qui se trouvait là en mémoire, ou 42.





2) l'OS ou le compilateur mettent toujours systématiquement à 0, c'est
un choix d'implémentation (idem, c'est pas comme ça que ça marche) ;



Je crois que j'ai déjà rencontré un compilateur idiot qui mettait
systématiquement les variables à 0 en mode debug, et ne le faisait
pas en mode release (pour le jeu de parametre par defaut de
debug/release).
Evidemment, ca donne des resultats interessants, un programme qui
fonctionne comme attendu en mode debug peut faire n'importe quoi
une fois optimise...

Sur le compilateur xlC que j'ai sous la main, il y a une option
-qinitauto pour donner une valeur initiale specifique et connue
au variables automatiques :

#include <iostream>
int main() {
int i ;
std::cout << std::hex << i << "n" ;
}

xlC -qinitauto init.cc
"init.cc", line 6.30: 1540-1102 (W) "i" might be used before it is set.

./a.out
ffffffff

Et si on n'utilise pas cette option, on a bien une valeur par defaut,
un peu plus explicite:

xlC -qinitauto init.cc
"init.cc", line 6.30: 1540-1102 (W) "i" might be used before it is set.

./a.out
deadbeaf

la premiere fois, ca surprend ;)
Rémi Moyen
Le #19705801
On 6 juil, 11:04, Michael Doubez
As tu essayé avec divers degré d'optimisation ? Si je me souviens
bien, j'ai eu ce cas pour un programme qui marchait bien en mode debug
mais qui plantait en -02 à cause d'une variable non initialisée qui
prenait une valeur aléatoire.



Je n'y avais pas pensé (et pourtant j'ai ajouté un -O1 rien que pour
pouvoir activer -Wuninitialized !). En l'occurrence, ça ne change rien
au résultat.

Tiens, à partir de -O3, j'ai un 2ème warning :

main.cpp: In function `void f()':
main.cpp:12: warning: 'v3' might be used uninitialized in this
function
main.cpp: In function `int main()':
main.cpp:12: warning: 'v3' might be used uninitialized in this
function

Amusant...
--
Rémi Moyen
Rémi Moyen
Le #19705791
On 6 juil, 10:56, Jean-Marc Bourguet
> Cependant, j'ai encore un doute avec le warning de g++ : pourquoi il
> ne m'a pas prévenu pour A::v5_ ?

> Est-ce que c'est parce qu'il n'arrive pas à tracer de manière fiabl e
> tout le code et qu'au moment où j'appelle A::f(), il est trop
> difficile pour lui de savoir si la variable a été initialisée ou non,

Vraisemblablement quelque chose du genre.



OK.

> Par curiosité et parce que j'aimerais bien le faire moi-même, tu pe ux
> me donner le programme modifié ?

Voici (remarque l'ajout du dummy[1] qui a ete necessaire, j'ai pas ete vo ir
l'assembleur genere pour comprendre pourquoi).



Merci ! Y'a juste une petite faute de frappe, la fonction devrait
s'appeler mainRemi(), pas mainRemy() (ou mainRémi(), si quelqu'un
arrive à mettre des accents dans un identifiant ?) ;-)
--
Rémi Moyen
Fabien LE LEZ
Le #19706031
On Mon, 6 Jul 2009 03:39:00 -0700 (PDT), Rémi Moyen

si quelqu'un
arrive à mettre des accents dans un identifiant ?



Je crois avoir lu quelque part que la norme l'autorise. Mais je ne
sais pas s'il existe des implémentations de cette mauvaise idée.
Publicité
Poster une réponse
Anonyme