Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Valeur d'une variable locale non-initialisée

28 réponses
Avatar
Rémi Moyen
Bonjour,

En relisant un bout de code, je suis tomb=E9 sur une classe qui contient
un int comme membre, et bien que cette variable ne soit jamais
initialis=E9e 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'=E9taient pas initialis=E9es =E0 0
automatiquement...

Si je regarde mon Stroustrup, il me dit (4.9.5) que seules les
variables globales ou statiques locales sont initialis=E9es =E0 0 par
d=E9faut, et qu'une variable non-initialis=E9e locale ou cr=E9=E9e sur le t=
as
a une valeur non-d=E9finie. Les variables membres d'une classe, dans
quelle cat=E9gorie tombent-elles ? J'aurais dit le deuxi=E8me 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 =E9t=E9 mises =E0 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 =E0 0 par hasard (apr=E8s tout,
une valeur "non-d=E9finie" par le standard peut tr=E8s bien =EAtre 0) ? Est=
-
ce une particularit=E9 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, =E7a m'aiderait pas mal... Merci
d'avance !
--
R=E9mi Moyen

8 réponses

1 2 3
Avatar
Jean-Marc Bourguet
"" writes:

On 7 juil, 10:02, James Kanze wrote:

> Enfin, pour revenir à ta question : tout ça, c'est la tout
> première phase de traduction, bien avant même la tokenisation.
> Il s'ensuit qu'un compilateur ne peut pas faire de distinction
> entre les caractères dans les identificateurs, dans les
> litéraux, et même dans les commentaires. Un compilateur qui
> accepte « été » dans un commentaire, dans un encodage
> quelconque, doit l'accepter aussi comme identificateur dans le
> même encodage ; formellement, ce que le compilateur voit après
> la première phase de traduction, c'est u00C9tu00C9 (ou quelque
> chose qu'il est obligé à traiter de façon identique). Où
> qu'apparaissent cette chaîne de caractères.

D'accord, nous avons donc eu la même compréhension du texte. J'hésite
à saisir un bug report à gcc.



Je crois qu'ils sont au courant. Doc de gcc:

Unless the experimental -fextended-identifiers option is used, GCC does not
permit the use of characters outside the ASCII range, nor `u' and `U'
escapes, in identifiers. Even with that option, characters outside the
ASCII range can only be specified with the `u' and `U' escapes, not used
directly in identifiers.

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
Avatar
James Kanze
On Jul 7, 6:12 pm, Jean-Marc Bourguet wrote:
"" wri tes:
> On 7 juil, 10:02, James Kanze wrote:



> > Enfin, pour revenir à ta question : tout ça, c'est la tout
> > première phase de traduction, bien avant même la tokenisation.
> > Il s'ensuit qu'un compilateur ne peut pas faire de distinction
> > entre les caractères dans les identificateurs, dans les
> > litéraux, et même dans les commentaires. Un compilateur qui
> > accepte « été » dans un commentaire, dans un encodage
> > quelconque, doit l'accepter aussi comme identificateur dans le
> > même encodage ; formellement, ce que le compilateur voit après
> > la première phase de traduction, c'est u00C9tu00C9 (ou quelque
> > chose qu'il est obligé à traiter de façon identique). Où
> > qu'apparaissent cette chaîne de caractères.



> D'accord, nous avons donc eu la même compréhension du texte.
> J'hésite à saisir un bug report à gcc.



Je crois qu'ils sont au courant. Doc de gcc:



Unless the experimental -fextended-identifiers option is used,
GCC does not permit the use of characters outside the ASCII
range, nor `u' and `U' escapes, in identifiers. Even with
that option, characters outside the ASCII range can only be
specified with the `u' and `U' escapes, not used directly in
identifiers.



Et je crois qu'ailleurs (constantes de chaîne, commentaires), je
ne crois pas qu'il les traite réelement non plus. L'erreur, s'il
y en a (et il y en a, s'ils veulent la conformité), c'est plutôt
dans le fait qu'ils n'analyse pas les caractères dans les
chaînes et les commentaires, à part chercher la fin, et qu'ils
passent ce qu'il y a dans le fichier d'entrée, sans le moindre
validation ni traitement.

Je ne sais pas, en revanche, s'ils considèreront une erreur. En
tout cas, ce n'est certainement pas une erreur grave.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
Jean-Marc Bourguet
James Kanze writes:

On Jul 7, 6:12 pm, Jean-Marc Bourguet wrote:
> "" writes:
> > On 7 juil, 10:02, James Kanze wrote:

> > > Enfin, pour revenir à ta question : tout ça, c'est la tout
> > > première phase de traduction, bien avant même la tokenisation.
> > > Il s'ensuit qu'un compilateur ne peut pas faire de distinction
> > > entre les caractères dans les identificateurs, dans les
> > > litéraux, et même dans les commentaires. Un compilateur qui
> > > accepte « été » dans un commentaire, dans un encodage
> > > quelconque, doit l'accepter aussi comme identificateur dans le
> > > même encodage ; formellement, ce que le compilateur voit après
> > > la première phase de traduction, c'est u00C9tu00C9 (ou quelque
> > > chose qu'il est obligé à traiter de façon identique). Où
> > > qu'apparaissent cette chaîne de caractères.

> > D'accord, nous avons donc eu la même compréhension du texte.
> > J'hésite à saisir un bug report à gcc.

> Je crois qu'ils sont au courant. Doc de gcc:

> Unless the experimental -fextended-identifiers option is used,
> GCC does not permit the use of characters outside the ASCII
> range, nor `u' and `U' escapes, in identifiers. Even with
> that option, characters outside the ASCII range can only be
> specified with the `u' and `U' escapes, not used directly in
> identifiers.

Et je crois qu'ailleurs (constantes de chaîne, commentaires), je
ne crois pas qu'il les traite réelement non plus. L'erreur, s'il
y en a (et il y en a, s'ils veulent la conformité), c'est plutôt
dans le fait qu'ils n'analyse pas les caractères dans les
chaînes et les commentaires, à part chercher la fin, et qu'ils
passent ce qu'il y a dans le fichier d'entrée, sans le moindre
validation ni traitement.



A lire leur doc sur le sujet, en dehors des identifieurs ils font ce qu'il
faut et ils ont des options pour changer les defauts (voir -finput-charset,
-fexec-charset, -fwide-exec-charset). Mais tu penses peut-etre a quelque
chose d'autre?

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
Avatar
James Kanze
On Jul 8, 1:25 pm, Jean-Marc Bourguet wrote:
James Kanze writes:
> On Jul 7, 6:12 pm, Jean-Marc Bourguet wrote:
> > ""
> > writes:
> > > On 7 juil, 10:02, James Kanze wrote:



> > > > Enfin, pour revenir à ta question : tout ça, c'est la
> > > > tout première phase de traduction, bien avant même la
> > > > tokenisation. Il s'ensuit qu'un compilateur ne peut
> > > > pas faire de distinction entre les caractères dans les
> > > > identificateurs, dans les litéraux, et même dans les
> > > > commentaires. Un compilateur qui accepte « été » dans
> > > > un commentaire, dans un encodage quelconque, doit
> > > > l'accepter aussi comme identificateur dans le même
> > > > encodage ; formellement, ce que le compilateur voit
> > > > après la première phase de traduction, c'est
> > > > u00C9tu00C9 (ou quelque chose qu'il est obligé à
> > > > traiter de façon identique). Où qu'apparaissent cette
> > > > chaîne de caractères.



> > > D'accord, nous avons donc eu la même compréhension du
> > > texte. J'hésite à saisir un bug report à gcc.



> > Je crois qu'ils sont au courant. Doc de gcc:



> > Unless the experimental -fextended-identifiers option is
> > used, GCC does not permit the use of characters outside
> > the ASCII range, nor `u' and `U' escapes, in
> > identifiers. Even with that option, characters outside the
> > ASCII range can only be specified with the `u' and `U'
> > escapes, not used directly in identifiers.



> Et je crois qu'ailleurs (constantes de chaîne,
> commentaires), je ne crois pas qu'il les traite réelement
> non plus. L'erreur, s'il y en a (et il y en a, s'ils veulent
> la conformité), c'est plutôt dans le fait qu'ils n'analyse
> pas les caractères dans les chaînes et les commentaires, à
> part chercher la fin, et qu'ils passent ce qu'il y a dans le
> fichier d'entrée, sans le moindre validation ni traitement.



A lire leur doc sur le sujet, en dehors des identifieurs ils
font ce qu'il faut et ils ont des options pour changer les
defauts (voir -finput-charset, -fexec-charset,
-fwide-exec-charset). Mais tu penses peut-etre a quelque
chose d'autre?



Il y a clairement une erreur dans la doc, puisque ces options
n'apparaissent pas dans la section « Option Summary ». Enfin, je
ne les connaissais pas non plus. Et je ne sais plus avec quelle
version j'ai fait mes essais. Mais si mes souvenirs sont
correct, c'était sous Solaris, dans un environement où mon
locale précisait ISO 8859-1 -- ce qui pourrait expliquer
pourquoi j'avais l'impression qu'ils passaient les caractères
sans les traiter. (En fait, du moment que tous les participants
(editeur, font d'affichage, etc.) sont d'accord sur l'encodage,
passer les bytes sans les traiter serait correct dans ses cas.)

Enfin, un essai rapide (et non exhaustif) avec la version du g++
installée ici (4.3.3) donne quand même des resultats un peu
étrange. Je fais des essais dans un locale où tous les $LC_XXX
sont à "C". En entrée, j'ai un fichier :

#include <iostream>

int
main()
{
std::cout << "été" << std::endl ;
return 0 ;
}

encodé en ISO 8859-1 (c-à-d avec un 0xE9 pour chacun des é). Si
je le compile (sans options) et je l'exécute, la sortie (passée
par od -t x1) est bien:
0000000 e9 74 e9 0a
En locale "C", il n'aurais pas dû accepter les 0xE9 dans le
fichier d'entrée ; s'il ignore le locale (mettons parse qu'il
considère que le locale "C" n'est pas positionné), selon sa
documentation, il doit traiter en UTF-8 ; or, en UTF-8, un octet
0xE9, suivi d'un octet avec le bit 7 à 0, n'est pas légal.

Si je remplace les 'é' par des "u00E9", il compile aussi, mais
en revanche, la sortie après od est :
0000000 c3 a9 74 c3 a9 0a
. De l'UTF-8, en somme.

Enfin, je modifie le fichier source pour utiliser UTF-8
(remplaçant les 0xE9 par des 0xC3, 0xA9), et je compile de
nouveau, sans modifier en quoique ce soit l'environement, et le
program sort bien de l'UTF-8. Je conclus donc qu'il passe les
octets tels quels, sans les regarder.

Tout ça, sans option. Si je donne l'option
-finput-charset=ISO8859-1, avec le premier essai (0xE9 pour les
'é'), le programme généré sort bien de l'UTF-8. L'option a l'air
de marcher, mais sans l'option, c'est un peu aléatoire, et non
comment décrit.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
Jean-Marc Bourguet
James Kanze writes:

On Jul 8, 1:25 pm, Jean-Marc Bourguet wrote:



Il y a clairement une erreur dans la doc, puisque ces options
n'apparaissent pas dans la section « Option Summary ».



Visiblement la synchronisation de la doc entre les differents documents et
partie de document n'est pas automatique.

Enfin, je ne les connaissais pas non plus. Et je ne sais plus avec quelle
version j'ai fait mes essais.



C'est a partir de 3.4.6 qu'il y a une section consacree aux charsets dans
le manuel du preprocesseur. Elle evolue dans le bon sens mais lentement de
version en version... Je crains que quand on arrive a un etat parfait, le
probleme ne se posera en fait plus.

Tout ça, sans option. Si je donne l'option -finput-charset=ISO8859-1,
avec le premier essai (0xE9 pour les 'é'), le programme généré sort bien
de l'UTF-8. L'option a l'air de marcher, mais sans l'option, c'est un peu
aléatoire, et non comment décrit.



Mon interpretation -- basee sur tes experiences, des souvenirs d'ancienne
version de la doc et de vieux essais personnels, cela fait longtemps que
j'ai passe toutes mes sources personnelles en UTF-8, et au boulot tout
reste en ASCII pur -- c'est que gcc suppose que c'est de l'UTF-8 mais ne le
valide pas (ce qui pour de l'ISO 8851 va vraisemblablement permettre de le
passer de maniere transparente, mais va poser des problemes pour d'autres
encodages plus complexes).

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
Avatar
espie
In article ,
Michael Doubez wrote:
On 6 juil, 11:12, Rémi Moyen wrote:
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.



C'est un des defauts de gcc: il a tendance a initialiser les variables
locales a 0 en -O0, et en -O1. Ce defaut disparait en -O2, mais c'est
souvent plus difficile a suivre avec le debugger. D'ou gros souci pour
le debutant.
Avatar
Michael Doubez
On 12 juil, 18:11, (Marc Espie) wrote:
In article com>,
Michael Doubez   wrote:
>On 6 juil, 11:12, Rémi Moyen wrote:
>> Bonjour,

>> En relisant un bout de code, je suis tombé sur une classe qui contie nt
>> 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.

C'est un des defauts de gcc: il a tendance a initialiser les variables
locales a 0 en -O0, et en -O1. Ce defaut disparait en -O2, mais c'est
souvent plus difficile a suivre avec le debugger.



Et, pour ajouter à la confusion, gcc ne détecte certains cas de
variables non initialisées qu'en mode -O2 car l'analyse de flux est
alors activée.

D'ou gros souci pour le debutant.



AMA le problème est alors un problème d'outil. valgrind, efence ou
même splint localisent facilement ce genre de problème.

--
Michael
Avatar
espie
In article ,
Michael Doubez wrote:
On 12 juil, 18:11, (Marc Espie) wrote:
C'est un des defauts de gcc: il a tendance a initialiser les variables
locales a 0 en -O0, et en -O1. Ce defaut disparait en -O2, mais c'est
souvent plus difficile a suivre avec le debugger.



Et, pour ajouter à la confusion, gcc ne détecte certains cas de
variables non initialisées qu'en mode -O2 car l'analyse de flux est
alors activée.



D'ou gros souci pour le debutant.





AMA le problème est alors un problème d'outil. valgrind, efence ou
même splint localisent facilement ce genre de problème.



En prenant splint en exemple, j'en suis revenu, car beaucoup trop verbeux...
je ne vois pas trop comment le reste peut detecter facilement des variables
non initialisees, sauf si elles font explicitement planter le code (et ne
se revelent pas une erreur de logique qui donne des resultats faux).

Perso, j'en reviens toujours au fait que gcc contient une foultitude
d'options, mais rarement celles qui seraient vraiment utiles. C'est toujours
un "dumping ground" pour le mec qui fait son boulot de recherche sur telle
ou telle optimisation absconse, et les warnings sont soit trop verbeux,
soit pas assez. Plus la paranoia de la FSF a ne pas decouper proprement en
back-end/front-end, des fois que quelqu'un s'en serve pour faire autre
chose... comme en plus gcc/g++ est leader dans son domaine specifique (logiciel
libre sous unix), les autres outils doivent "suivre" (comprendre des extensions
plus ou moins obscures de syntaxe, combien de fois splint m'a refuse
un fichier d'entetes de logiciel tiers qui utilisait des extensions gcc qu'il
ne connaissait pas... ca s'est un peu arrange depuis).

Sans compter que, refaire passer des outils, alors que gcc bouffe deja un
temps incroyable en verification de code pendant la compil', c'est quand meme
un peu derangeant...

J'ai quelques espoirs en llvm, qui devrait briser l'etat actuel des choses...
1 2 3