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

Comportement indéfini ou pas ?

40 réponses
Avatar
David Côme
Bonjour à tous.
Est ce que ce code à un comportement indéfini ?

//iostream est inclue , ...
int a; //(1)
cout<< a; // (2)

Pour ma part:
Je pense que la valeur de a est indéfinie car (1) créer une variable sur
la pile sans lui affecter de valeur.
Elle prend donc la valeur de ce qui se trouvait avant à cette place.
Il n'y a pas de moyen de connaitre cette valeur. La valeure de a est
indéfini même si certain compilo réalisé une affectation par défaut
(je pense à VC++ en mode débug , on peut confirmer ?)

Par contre la 2eme ligne, elle a un comportement totalement défini.Elle va
afficher la valeur de a, qui peut être n'importe quoi.

Suis-je dans le vrai ?

Merci.

10 réponses

1 2 3 4
Avatar
Fabien LE LEZ
On Wed, 27 Feb 2008 18:56:42 +0100, David Côme :

int a; //(1)


Jusque-là, pas de problème, même si l'utilité d'un tel code m'échappe.

cout<< a; // (2)


C'est de toutes façons un comportement indéfini : dans le meilleur des
cas, ça affichera un entier, sans qu'il soit possible d'en prévoir la
valeur à l'avance.

Il me semble que selon la norme, c'est un comportement indéfini tout
court (On ne peut pas du tout prévoir le comportement du code) ;
toutefois, en pratique, je m'attendrais à ce qu'un entier quelconque
soit effectivement affiché. Et il y a même de bonnes chances pour que
ce soit le même à chaque exécution, tant qu'on ne recompile pas.

Avatar
Anthony Fleury
Bonjour à tous.


Bonjour,

Est ce que ce code à un comportement indéfini ?

//iostream est inclue , ...
int a; //(1)
cout<< a; // (2)

Pour ma part:
Je pense que la valeur de a est indéfinie car (1) créer une variable sur
la pile sans lui affecter de valeur.
Elle prend donc la valeur de ce qui se trouvait avant à cette place.
Il n'y a pas de moyen de connaitre cette valeur. La valeure de a est
indéfini même si certain compilo réalisé une affectation par défaut
(je pense à VC++ en mode débug , on peut confirmer ?)

Par contre la 2eme ligne, elle a un comportement totalement défini.Elle
va afficher la valeur de a, qui peut être n'importe quoi.

Suis-je dans le vrai ?


Si on considère la plupart des implémentations connues, ça donnera en
effet un affichage d'une valeur aléatoire et en effet le comportement
peu changer en mode debug selon les compilateurs.

Cependant, au regard de la norme, ce code est indéfini car accède à une
variable non initialisée (en considérant (1) automatique).

Entre autre, a peut très bien contenir une valeur "invalide" pour le
système ("trap value") qui ferait remarquer au-dit système que la
variable utilisée ne l'est pas d'une manière conforme.

Anthony

Avatar
David Côme
On Wed, 27 Feb 2008 19:10:55 +0100, Fabien LE LEZ
wrote:

On Wed, 27 Feb 2008 18:56:42 +0100, David Côme :

int a; //(1)


Jusque-là, pas de problème, même si l'utilité d'un tel code m'échappe.



Ce code n'a pas d'utilité propre. C'est juste pour illustre l'utilisation
d'une variable non initialisée.

cout<< a; // (2)


C'est de toutes façons un comportement indéfini : dans le meilleur des
cas, ça affichera un entier, sans qu'il soit possible d'en prévoir la
valeur à l'avance.

Normal.


Il me semble que selon la norme, c'est un comportement indéfini tout
court (On ne peut pas du tout prévoir le comportement du code) ;
Je ne savais pas.


toutefois, en pratique, je m'attendrais à ce qu'un entier quelconque
soit effectivement affiché. Et il y a même de bonnes chances pour que
ce soit le même à chaque exécution, tant qu'on ne recompile pas.



Comme moi.


Avatar
Jean-Marc Bourguet
Fabien LE LEZ writes:

On Wed, 27 Feb 2008 18:56:42 +0100, David Côme :

int a; //(1)


Jusque-là, pas de problème, même si l'utilité d'un tel code m'échappe.

cout<< a; // (2)


C'est de toutes façons un comportement indéfini : dans le meilleur des
cas, ça affichera un entier, sans qu'il soit possible d'en prévoir la
valeur à l'avance.

Il me semble que selon la norme, c'est un comportement indéfini tout
court (On ne peut pas du tout prévoir le comportement du code) ;


J'ai pas vérifié, mais c'est ce que je pense. En particulier, ça peut être
une valeur déclanchant une exception (trois cas plausibles: la
représentation de ce qui serait -0 sur une machine en complément à 1 ou
grandeur et signe qui n'admet pas de -0; mauvais tags sur une machine où
les valeurs ont un tag; il y a eu une machine n'ayant que des nombres en
virgule flottante, mais où certaines opérations trappaient si une donnée
n'était pas entière).

toutefois, en pratique, je m'attendrais à ce qu'un entier quelconque soit
effectivement affiché.


Sur les machines courantes, c'est le comportement le plus vraissemblable.

Et il y a même de bonnes chances pour que ce soit le même à chaque
exécution, tant qu'on ne recompile pas.


Ca dépend de ce que tu appelles exécution. Ca ne m'étonnerait pas trop que
ceci

void f(int i) { int k = i; }
void g() { int a; std::cout << a << std::endl; }

int main() {
f(42);
g();
f(36);
g();
}

affiche 42 puis 36.

Et ca dépend aussi du système, tous ne remettent pas toute la mémoire à 0
entre processus (c'est certainement une mauvaise idée de ne pas le faire
sur des machines à usage général).

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
Sylvain
Anthony Fleury wrote on 27/02/2008 19:29:

Est ce que ce code à un comportement indéfini ?

//iostream est inclue , ...
int a; //(1)
cout<< a; // (2)

Entre autre, a peut très bien contenir une valeur "invalide" pour le

système ("trap value") qui ferait remarquer au-dit système que la
variable utilisée ne l'est pas d'une manière conforme.


j'ai du mal à saisir la finesse de l'indéfinition.
je ne vois ici qu'une imprévision (non connaissance d'une valeur
aléatoire, ou comment se paraphraser).

surtout je ne vois pas ce que serait un *int* "invalide" !!
vous avez des machines sur lesquelles un int, disons 32 bits, peut
contenir toutes les valuers entières entre 0x00000000 et 0xFFFFFFFF
*plus* d'autres valeurs invalides ???

Sylvain.


Avatar
Gabriel Dos Reis
Sylvain writes:

| Anthony Fleury wrote on 27/02/2008 19:29:
| >
| >> Est ce que ce code à un comportement indéfini ?
| >>
| >> //iostream est inclue , ...
| >> int a; //(1)
| >> cout<< a; // (2)
| >>
| > Entre autre, a peut très bien contenir une valeur "invalide" pour le
| > système ("trap value") qui ferait remarquer au-dit système qu e la
| > variable utilisée ne l'est pas d'une manière conforme.
|
| j'ai du mal à saisir la finesse de l'indéfinition.
| je ne vois ici qu'une imprévision (non connaissance d'une valeur
| aléatoire, ou comment se paraphraser).
|
| surtout je ne vois pas ce que serait un *int* "invalide" !!
| vous avez des machines sur lesquelles un int, disons 32 bits, peut
| contenir toutes les valuers entières entre 0x00000000 et 0xFFFFFFFF
| *plus* d'autres valeurs invalides ???

So ?

-- Gaby
Avatar
Sylvain
Gabriel Dos Reis wrote on 27/02/2008 23:37:
|
| surtout je ne vois pas ce que serait un *int* "invalide" !!
| vous avez des machines sur lesquelles un int, disons 32 bits, peut
| contenir toutes les valuers entières entre 0x00000000 et 0xFFFFFFFF
| *plus* d'autres valeurs invalides ???

So ?


so, vous avez des machines sur lesquelles un int, disons 32 bits,
peut contenir toutes les valuers entières entre 0x0 et 0xFFFFFFFF
*plus* d'autres valeurs, accessoirement invalides ???

la hiérarchie fr. utilise ISO-8859-1 pas UTF-8.

Sylvain.

Avatar
Sylvain
Gabriel Dos Reis wrote on 27/02/2008 23:37:
|
| surtout je ne vois pas ce que serait un *int* "invalide" !!
| vous avez des machines sur lesquelles un int, disons 32 bits, peut
| contenir toutes les valuers entières entre 0x00000000 et 0xFFFFFFFF
| *plus* d'autres valeurs invalides ???

So ?


so, vous avez des machines sur lesquelles un int, disons 32 bits,
peut contenir toutes les valuers entières entre 0x0 et 0xFFFFFFFF
*plus* d'autres valeurs, accessoirement invalides ???

la hiérarchie fr. utilise ISO-8859-1 pas UTF-8.

Sylvain.

Avatar
Gabriel Dos Reis
Sylvain writes:

| Gabriel Dos Reis wrote on 27/02/2008 23:37:
| > | | surtout je ne vois pas ce que serait un *int* "invalide" !!
| > | vous avez des machines sur lesquelles un int, disons 32 bits, peut
| > | contenir toutes les valuers entières entre 0x00000000 et 0xFFFFF FFF
| > | *plus* d'autres valeurs invalides ???
| > So ?
|
| so, vous avez des machines sur lesquelles un int, disons 32 bits,
| peut contenir toutes les valuers entières entre 0x0 et 0xFFFFFFFF
| *plus* d'autres valeurs, accessoirement invalides ???

et donc ?

-- Gaby
Avatar
Jean-Marc Bourguet
Sylvain writes:

surtout je ne vois pas ce que serait un *int* "invalide" !!


J'ai donné 3 cas de machines ayant existés où la non initialisation
pourrait fournir un int invalide. Je ne sais pas s'il y a eu des
implémentations de C++ pour ces machines, mais le C++ est conçu pour y
permettre une implémentation sans lui imposer d'initialiser toutes les
variables. On peut aussi parfaitement imaginer une implémentation qui
vérifierait dynamiquement la non utilisation de variables non intialisées.

Une autre source de problèmes, même avec des machines où toutes les
représentations sont valides, ce sont les optimisations. A partir du
moment où le comportement est formellement indéfini, le compilateur peut
supposer qu'il n'arrive pas et laisser ses algorithmes d'optimisation se
comporter n'importe comment si l'hypothèse n'est pas vraie. N'importe
comment, ca peut avoir des effets non causals, ou inconsitants.

int x; //0
for (i = 0; i < 10; ++i) {
if (f(i)) x = g(i);
}
std::cout << x << std::endl; //1
int y;
for (i = 0; i < 10; ++i) {
if (h(i)) { y = p(i); x = q(i); }
}
std::cout << x << " " << y << std::endl; //2

peut parfaitement afficher deux fois des valeurs différentes pour x même si
f(i) et h(i) ne retourne jamais true. Raisonnement pas hors de portée des
techniques d'optimisation actuelles:

x est non initialisé en 0, utilisé en 1 donc on assigne une valeur entre
les deux.

même raisonnement pour y entre 1 et 2. Mais si y est assigné entre 1 et 2,
x l'est aussi, donc x a deux utilisations distinctes (entre 0 et 1 et entre
1 et 2) et donc la valeur de x ne doit pas être conservée après 1, pour
diminuer la pression sur l'allocateur de registre, on introduit une
variable en plus pour ce deuxième intervalle.

L'allocateur fait son boulot et assigne des registres différents à x pour x
entre 0 et 1 et entre 1 et 2. Résultat, deux valeurs différentes pour x
sont affichées.

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

1 2 3 4