Petite question sur if( x || y || z)

Résolu
G0ss3Yn Messages postés 65 Date d'inscription dimanche 12 janvier 2003 Statut Membre Dernière intervention 5 novembre 2010 - 5 nov. 2010 à 20:34
G0ss3Yn Messages postés 65 Date d'inscription dimanche 12 janvier 2003 Statut Membre Dernière intervention 5 novembre 2010 - 5 nov. 2010 à 22:33
Bonjour,
J'ai lu je ne sais plus où (ou en tout cas j'ai ça en tête) que le test

if( x || y || z) paf( ) ;


est en fait la même chose que :

if( x )
  if( y )
    if( z )
       paf( ) ;


J'ai donc créé un code de test qui est le suivant :

#include "stdafx.h"

int Test( ) { return ( rand( ) % 10 ) ; }
int randTest = rand( ) % 2 ;

int _tmain(int argc, _TCHAR* argv[])
{
if( randTest || Test( ) ) printf( "test" ) ;

return 0;
}


Et que j'ai ensuite décompilé :

.text:00401000 _wmain          proc near               ; CODE XREF: ___tmainCRTStartup+10Ap
.text:00401000                 cmp     dword_403370, 0
.text:00401007                 jnz     short loc_40101B
.text:00401009                 call    ds:rand
.text:0040100F                 cdq
.text:00401010                 mov     ecx, 0Ah
.text:00401015                 idiv    ecx
.text:00401017                 test    edx, edx
.text:00401019                 jz      short loc_401029
.text:0040101B
.text:0040101B loc_40101B:                             ; CODE XREF: _wmain+7j
.text:0040101B                 push    offset Format   ; "test"
.text:00401020                 call    ds:printf
.text:00401026                 add     esp, 4
.text:00401029
.text:00401029 loc_401029:                             ; CODE XREF: _wmain+19j
.text:00401029                 xor     eax, eax
.text:0040102B                 retn
.text:0040102B _wmain          endp


Donc tout va bien. Mais ma question est la suivante : Est-ce que c'est un comportement sur lequel on peut compter ? Est-on sûr, est-ce un standard ou quoi que ce soit ? Parce que si un jour je tombe sur un compilateur qui fait par exemple les tests à l'envers et que lors de l'écriture du code je compte sur le comportement inverse... ouch :)

Je pense en particulier à un code de fonction dans une classe qui testerai si la classe est initialisée et qui tenterai de l'initialiser si elle ne l'est pas :

void CUneClasse::UneFonction( )
{
  if( m_bDejaInitialise || this->Initialise() ) etc...
}


Bien sûr tout ceci est une question de culture, je pourrai évidemment écrire :

if( !m_bDejaInitialise ) this-> Initialise( ) ;
if( m_bDejaInitalise ) etc...


Merci à vous.

G0ss3Yn

8 réponses

DeAtHCrAsH Messages postés 2670 Date d'inscription vendredi 25 janvier 2002 Statut Membre Dernière intervention 6 février 2013
5 nov. 2010 à 22:19
En fait je vois deux choses dans ta question.

1) Premiere chose :

Avec le code suivant :
int a = 2;
int b = 4;
int c = 6;

int d = a+b*c; // Ici d vaudra 26 car la multiplication est prioritaire sur l'addition
int e = (a+b)*c; // Ici e vaudra 36 car les parenthèses sont prioritaires

Conclusion : La regle apprit a l'école et aussi vrai en programmation

2) Deuxième chose :

Avec le code suivant:
if(x || y)

Rien ne garanti que le compilateur ne vas pas générer du code assembleur qui va d'abord évaluer y et ensuite x.
Malgré ca tout les compilo avec lesquels j'ai déjà travaillé, vont d'abord évaluer x et ensuite y.
Ils partent sur le principe ou il revient au programmeur d'organiser son code pour qu'il soit le plus performant possible.

Mais je répète cela n'est pas une généralité. Il se peut que demain tu tombes sur un compilo qui evaluera y et ensuite x, d'ou l'interet de bétonner ton code en y ajoutant des controles dès que tu sens que cela est nécéssaire.

Shell
3
DeAtHCrAsH Messages postés 2670 Date d'inscription vendredi 25 janvier 2002 Statut Membre Dernière intervention 6 février 2013
5 nov. 2010 à 20:43
Salut,

Ton code est faux.

Le test

if( x )
  if( y )
    if( z )
       paf( ) ;


est égale a

if(x && y && z) paf();


Cela est toujours vrai!

Shell
0
G0ss3Yn Messages postés 65 Date d'inscription dimanche 12 janvier 2003 Statut Membre Dernière intervention 5 novembre 2010
5 nov. 2010 à 20:47
Ah oui en effet.
C'est plutôt

if( x ) paf( ) ;
else
  if( y ) paf( ) ;
  else
    if( z ) paf( ) ;



Mais concernant la suite ?


G0ss3Yn
0
DeAtHCrAsH Messages postés 2670 Date d'inscription vendredi 25 janvier 2002 Statut Membre Dernière intervention 6 février 2013
5 nov. 2010 à 20:54
Concernant la suite, le bout de code suivant sera toujours vrai quelque soit le compilateur.
Si un compilo change l'ordre des instructions mets le direct a la poubelle!

void CUneClasse::UneFonction( )
{
if( m_bDejaInitialise || this->Initialise() ) etc...
}

Malgré cela meme si t'es instruction sont inversées, dans ta fonction Initialise() tu devrais toujours faire le test qui verifie si la classe n'est pas deja initialisée. Cela s'applique par mesure de sécurité, au cas ou la fonction serais appellée deux fois de suite par un codeur un peu fatigué.
Ainsi quelque soit l'ordre d'execution de la condition, elle ne posera jamais problème.

Shell
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
G0ss3Yn Messages postés 65 Date d'inscription dimanche 12 janvier 2003 Statut Membre Dernière intervention 5 novembre 2010
5 nov. 2010 à 21:19
D'accord avec toi pour le code, mais ma question n'est pas là ^^
D'accord aussi avec le fait qu'un compilo qui réorganise ça c'est pas sympa :)

J'me disais juste que c'est bien "défini" quelque part ce comportement ?
J'ai trouvé ça sur le langage C : http://fr.wikibooks.org/wiki/Programmation_C/Op%C3%A9rateurs

Et on lit :
La priorité (quel opérateur est appliqué avant, en l'absence de parenthèses explicite) et l'associativité (dans quel ordre sont traités les arguments des opérateurs ayant la même priorité) sont résumées dans la table suivante (par ordre décroissant de priorité - les opérateurs décrits dans un autre chapitre ont un lien dédié) :


Et dans le tableau :


|| binaire GD ou logique avec séquencement


Donc "associativité" gauche vers droite. Quelqu'un sait si ça vient de là ?
A moins que ça soit juste "par convention", ou dépendant du compilateur.


G0ss3Yn
0
DeAtHCrAsH Messages postés 2670 Date d'inscription vendredi 25 janvier 2002 Statut Membre Dernière intervention 6 février 2013
5 nov. 2010 à 21:25
On parle de compilateur, donc pas de convention bien particulière concernant ce point. Chacun est libre de créer son compilateur comme il l'entend.

D'autre part ton article parle des regles de priorités et non de l'ordre dans le quel le compilo va retranscrire tes lignes de codes.

A l'école primaire on a deja du te dire que les multiplications et les divisions sont prioritaire sur les additions et les soustractions.

Ben ton article c'est la même chose.

Shell
0
G0ss3Yn Messages postés 65 Date d'inscription dimanche 12 janvier 2003 Statut Membre Dernière intervention 5 novembre 2010
5 nov. 2010 à 21:52
C'est bien ma question : Est-ce que cette règle (de l'école primaire) est aussi appliquée ici ? mais tu y as surement répondu juste avant :

On parle de compilateur, donc pas de convention bien particulière concernant ce point. Chacun est libre de créer son compilateur comme il l'entend.


Donc merci beaucoup à toi.


G0ss3Yn
0
G0ss3Yn Messages postés 65 Date d'inscription dimanche 12 janvier 2003 Statut Membre Dernière intervention 5 novembre 2010
5 nov. 2010 à 22:33
Oui je suis d'accord, et puis j'ai trouvé ça : http://www.fh-jena.de/~kleine/history/languages/Stroustrup-CplusplusReferenceManual.pdf

Page 16, 7.12 concernant l'opérateur || :

Unlike |, || guarantees left-to-right evaluation. Moreover, the second operand is not evaluated if the value of the first operand is not zero.

Donc comme tu dis si un compilo respecte pas ça, poubelle :)

Merci.

G0ss3Yn
0
Rejoignez-nous