IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Ordre d'évaluation des conditions dans un if


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 15
    Par défaut Ordre d'évaluation des conditions dans un if
    Bonsoir,

    J'ai le problème de compréhension suivant :
    Dans un livre consacré au langage C++ il est dit que :
    (1)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if ( i < max && (j++ == 10))
    n'est pas équivalent à :
    (2)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    j++;
    (i < max && (j == 10));
    "Car l'opérateur && n'évalue son second opérande que lorsque cela est nécessaire. D'où dans la première formulation, l'expression j++ n'est pas évaluée lorsque la condition (i < max) est fausse; elle l'est, en revanche, dans la deuxième formulation."?????
    Je ne comprends pas cette explication. Pour moi en (2) les parenthèses forcent l'évaluation de (j) en premier puis l'évaluation de ( i < max) si j est vrai ?...
    En (1) même raisonnement ... Donc équivalence ?

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Ton erreur de compréhension vient que les choses ne se passent pas au niveau des parenthèses, mais bien au niveau de l'opérateur logique &&.

    L'opérateur logique && est correspond à un AND "optimisé", et, pour comprendre ce que je vais t'expliquer, rien ne vaut la table de vérité pour AND

    si tu mets deux expressions pouvant chacune être représentée par une valeur "vrai" ou "faux" dans une relation AND, tu te trouves confronté à quatre combinaisons possible, avec les résultat suivants:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    expr1 | expr2 | expr1 AND expr2
    faux  | faux  |   faux
    faux  | vrai  |   faux
    vrai  | faux  |   faux
    vrai  | vrai  |   vrai
    Tu constateras que, sur les quatre combinaisons possibles, trois donneront "faux" comme résultat et une seule donnera "vrai" comme résultat.

    La combinaison donnant une valeur "vrai" comme résultat est ce que l'on appelle "l'état unique".

    Tu constateras aussi que le résultat sera d'office "faux" si la première expression correspond déjà à la valeur "faux".

    Si l'on dit que l'opérateur && est un opérateur "optimisé", c'est simplement parce que, s'il arrive à déterminer, après avoir évalué une (ou plusieurs) expression(s) que le résultat ne sera de toutes façons pas l'état unique, il n'évaluera purement et simplement pas l'expression suivante.

    Ainsi, lorsque l'on est confronté à un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if ( i < max && (j++ == 10))
    j++ ne sera effectué que si i est bel et bien plus petit que max.

    Si i est égal (ou supérieur) à max, la deuxième expression (j++==10) ne sera purement et simplement pas évaluée, et j ne sera donc même pas incrémenté.

    Par contre, avec un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    j++;
    if(i < max && (j == 10))
    j est incrémenté de manière inconditionnelle (quelle que puisse être la valeur de j ou celle de i) et ce n'est qu'après avoir incrémenté j que l'on va vérifier si i est bel et bien plus petit que max et que j est égal à 10.

    Est-ce que cette explication te semble plus claire
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 287
    Par défaut
    Ton erreur de compréhension vient que les choses ne se passent pas au niveau des parenthèses
    C'est drôle. J'aurais dit exactement l'inverse.

    Si tu as: 0*(12+13+56+4+6+65+9+9+8+7+8), vas-tu te casser le tronc à calculer la somme d'abord?

    Non. Tu commences par évaluer le premier facteur du produit, puis le deuxième. Je ne vois pas ce qui peut choquer.

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    C'est drôle. J'aurais dit exactement l'inverse.

    Si tu as: 0*(12+13+56+4+6+65+9+9+8+7+8), vas-tu te casser le tronc à calculer la somme d'abord?

    Non. Tu commences par évaluer le premier facteur du produit, puis le deuxième. Je ne vois pas ce qui peut choquer.
    Attention, là, tu parles d'opérateurs mathématique (multiplication et addition).

    Je t'avouerai que je ne sais pas du tout comment le compilateur réagit lorsque l'on essaye d'effectuer une multiplication par 0.

    Mais je pourrais faire valoir que, dans ton exemple, la somme est purement et simplement une constante de compilation, et que le produit l'est donc aussi.

    Le compilateur pourrait tout aussi bien évaluer les expressions dans l'ordre de leur priorité : les parenthèses en premier lieu et terminer par la multiplication, tout comme il pourrait tout aussi bien être "assez intelligent" que pour déterminer que 0 * n'importe quoi sera toujours égal à 0

    Or, le problème est posé avec un opérateur logique (AND), et plus précisément avec un opérateur logique optimisé

    [EDIT]Visiblement, tu n'as peut etre pas compris ce que je disais...

    Je disais que le code if ( i < max && (j++ == 10)) va d'abord et avant tout évaluer l'expression i<max.

    Il obtiendra donc une valeur qui sera égale à true si i est bel et bien plus petit que max et à false si i est plus grand ou égal à max.

    Si la valeur est "false", il n'y a aucune raison d'évaluer la deuxième expression, car on sait que la réponse sera toujours false.

    Or cette deuxième expression est elle-même composée de deux expression
    • j++ d'une part (qui incrémente j)
    • j == 10 qui est une expression booléene
    il comme il n'évalue pas l'exression complete, aucune de ces deux "sous expression" n'est évaluée, et j n'est donc pas incrémenté
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Et puis c'est aussi un comportement imposé par la norme (du moins en C donc en C++ j'imagine que ce n'est pas différent).
    C'est ce qui permet d'écrire des choses comme if ( (ptr!=NULL) && (ptr->level<12) ) { ... sans déréférencer un pointeur NULL.

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par kwariz Voir le message
    Et puis c'est aussi un comportement imposé par la norme (du moins en C donc en C++ j'imagine que ce n'est pas différent).
    C'est ce qui permet d'écrire des choses comme if ( (ptr!=NULL) && (ptr->level<12) ) { ... sans déréférencer un pointeur NULL.
    Exactement, le comportement de l'opérateur && (tout comme celui de || et de ^ ) est hérité tout droit du C
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 287
    Par défaut
    Non mais ça vient simplement du fait que les opérations sont effectuées de gauche à droite.

    Prenons un opérateur non optimisé pour nous en convaincre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     i = -1; 
    if ( valeurAbsolueQuiModifiei(i) == ( i++ ) )
    J'imagine que i vaut 2 à la fin

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     i = -1; 
    if ( ( i++ ) == valeurAbsolueQuiModifiei(i) )
    J'imagine que i vaut 0 à la fin


    Y a pas de questions de parenthèses, d'optimisation ou de C.

  8. #8
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Je m’immisce un peu dans le monde C++, mais en C la norme garantit un point de séquence après l'évaluation de la première opérande des opérateurs &&, || et , mais pas des autres comme ==. Une expression comme if ( valeurAbsolueQuiModifiei(i) == ( i++ ) ) a un comportement indéfini.
    Mais c'est à vérifier.

  9. #9
    Membre Expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    Non mais ça vient simplement du fait que les opérations sont effectuées de gauche à droite.

    Prenons un opérateur non optimisé pour nous en convaincre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     i = -1; 
    if ( valeurAbsolueQuiModifiei(i) == ( i++ ) )
    J'imagine que i vaut 2 à la fin

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     i = -1; 
    if ( ( i++ ) == valeurAbsolueQuiModifiei(i) )
    J'imagine que i vaut 0 à la fin


    Y a pas de questions de parenthèses, d'optimisation ou de C.
    Heu c'est certain qu'ils sont evalue dans cet ordre la? Je pensais que c'etait non-definis et qu'on ne peut pas se baser sur l'ordre d'evaluation dans ce genre de cas...

  10. #10
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    Non mais ça vient simplement du fait que les opérations sont effectuées de gauche à droite.

    Prenons un opérateur non optimisé pour nous en convaincre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     i = -1; 
    if ( valeurAbsolueQuiModifiei(i) == ( i++ ) )
    J'imagine que i vaut 2 à la fin

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     i = -1; 
    if ( ( i++ ) == valeurAbsolueQuiModifiei(i) )
    J'imagine que i vaut 0 à la fin


    Y a pas de questions de parenthèses, d'optimisation ou de C.
    Là, tu n'as qu'une expression booléenne, ce qui est encore différent!

    Pour que tu puisse obtenir un résultat booléen, (qui puisse décider si tu rentre ou non dans le cas "vrai"), il faudra fatalement que tu évalues les deux parties de l'expression "=="

    Or, ce dont on parle c'est d'une expression booléenne qui vérifie deux condition
    1. i < max d'une part ET
    2. j++ == 10 d'autre part
    ou, si tu préfères, tu te retrouve avec un AST proche de

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
          AND
        /    \
       /      \
      <        ==
     / \      /   \
    i  max   +=   10
             / \
            j   1
    Quand on va rencontrer le AND, on va, effectivement passer en priorité dans la branche gauche.

    Là, on se rend compte que l'on a affaire à une nouvelle expression (i < max) qui nous renvoie une valeur booléenne.

    C'est chouette, parce que AND permet justement choisir de passer (ou non) quelque part en fonction des valeurs booléennes.

    Si c'était "juste" un AND non optimisé, (comme cela pourrait l'être sous la forme de (if (i<max & (j++ == 10)) ) on passerait d'office dans la branche droite du AND, et l' on remarquerait que l'expression j++ == 10 (qui est aussi une expression booléenne vu qu'elle utilise l'opérateur == ) est en fait composé d'une autre expression (j++ que j'ai traduit un peut honteusement par j+=1 ) qu'il faudrait évaluer afin de pouvoir donner le résultat.

    Mais nous sommes face à l'opérateur optimisé &&!!!

    L'optimisation qu'il est capable de faire est qu'il peut "laisser tomber toute expression qui ne pourrait en aucun cas modifier le résultat final".

    Alors, bien sur, il va commencer par l'expression de gauche!

    Et il y aura, comme je l'ai dit, deux solutions:
    Soit i est effectivement plus petit que max, et, dans ce cas là, il devra vérifier l'expression de droite.

    Soit i est plus grand ou égal à max, et, dans ce cas, le résultat de l'expression suivante ne changera plus rien au résultat final : ce sera de toutes manière faux.

    Dans ce deuxième cas, il décide donc de ne pas évaluer l'expression de droite, et donc, la sous expression (traduite par j+=1) n'est pas effectuée
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    Non mais ça vient simplement du fait que les opérations sont effectuées de gauche à droite.

    Prenons un opérateur non optimisé pour nous en convaincre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     i = -1; 
    if ( valeurAbsolueQuiModifiei(i) == ( i++ ) )
    J'imagine que i vaut 2 à la fin

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     i = -1; 
    if ( ( i++ ) == valeurAbsolueQuiModifiei(i) )
    J'imagine que i vaut 0 à la fin


    Y a pas de questions de parenthèses, d'optimisation ou de C.
    Non, l'ordre d'évaluation entre les deux opérandes de l'opérateur == n'est pas garanti, les deux choix possible (en plus du souci de séquencement évoqué par kwariz).

Discussions similaires

  1. Ordre de l'évaluation des conditions
    Par NeraOne dans le forum VB.NET
    Réponses: 5
    Dernier message: 18/07/2012, 15h44
  2. Ordre des conditions dans une clause WHERE, important ou pas en 2012 ?
    Par clavier12AZQSWX dans le forum Langage SQL
    Réponses: 5
    Dernier message: 07/03/2012, 11h54
  3. [MySQL] Influence de l'ordre des conditions dans la clause WHERE
    Par morgan47 dans le forum PHP & Base de données
    Réponses: 5
    Dernier message: 09/02/2012, 22h46
  4. Ordre de vérification des conditions dans un "if"
    Par LDPDC dans le forum Général Java
    Réponses: 6
    Dernier message: 20/04/2009, 13h44
  5. Réponses: 1
    Dernier message: 10/03/2006, 22h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo