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 :

enchainement de conditions dans un if


Sujet :

C

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Par défaut enchainement de conditions dans un if
    Bonjour,

    Une question un peu tordu peut etre ?
    Est ce qu'on peut faire ceci, est ce que cela a un comportement défini ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    int a;
    [...]
    if( a == 0 && FonctionQuiChangeA(&a) && a == 0)
    {
        //du code
    }
    Merci

  2. #2
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Par défaut
    Personnellement, je le ferai pas déjà pour ne pas avoir à me poser la question et m'enlever le mal de tête

    et puis je ne sais pas comment l'optimiseur il va réagir en voyant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if( (a == 0) && (a == 1) )
    Même si il y a des trucs au milieu, il peut se dire (à tord dans ce cas) "la condition est toujours fausse" car a ne peut être égal à 0 et à 1 en même temps
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  3. #3
    Membre confirmé Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Par défaut
    C'est même certain !
    Cette condition sera toujours évaluée à FALSE.
    Certains compilo (avec l'option qui va bien) te le signalerons avec un warning (un truc du genre "conditional expression is constant").

    Regle d'or : choisir l'option qui permet d'afficher tous les warning et n'en laisser aucun !
    Comme ça, quand tu modifies ton code et qu'un nouveau warning apparaît, tu le vois tout de suite.

    Hadrien

  4. #4
    Membre Expert
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Par défaut
    Citation Envoyé par sopsag Voir le message
    C'est même certain !
    Cette condition sera toujours évaluée à FALSE.
    J'en doute. L'important ici, c'est FonctionQuiChangeA(&a). L'operateur && introduit un point de sequence, donc le compilateur ne peut pas simplifier le test. Puisqu'il est garanti que l'evaluation de l'expression se fait de gauche a droite, alors je ne vois aucun probleme avec ce code (sauf que c'est assez moche). Dans le meme ordre d'idee,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    c = getchar()) != EOF && c != '\n'
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    p != NULL && *p == '\0'
    sont parfaitement surs.

  5. #5
    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,

    La règle de base est de toujours éviter les effets de bord lorsque tu peux...

    [EDIT]Un effet de bord est le résultat que l'on obtient lorsqu'une instruction a pour effet de modifier une valeur que l'on est déjà occupé à traiter par ailleurs (définition simple mais suffisante )
    [/EDIT]

    L'opérateur logique && est, si c'est la même chose qu'en C++, optimisé.

    Cela signifie que, dans le cas de l'opérateur &&, l'expression se trouvant à sa droite ne sera évaluée que si l'expression complète a encore une chance de donner un résultat à true.

    Cela implique que, si la première expression (celle qui se trouve à gauche de l'opértateur &&) est fausse, la deuxième (celle qui se trouve à sa droite) ne sera jamais évaluée, et donc, que les modifications que tu peux attendre de cette expression (qui est ici un appel de fonction) risquent de n'être jamais effectuées.

    En effet, pour l'opérateur logique &&, tu as une table de vérité qui prend la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    expr A | expr B | A && B
    false  | false  | false
    false  | true   | false
    true   | false  | false
    true   | true   | true
    Dés lors, si tu considère que, dans ton expression i==0 && fonctionModifiantI
    i==0 est l'epression A et que foncitonModifiantI est l'expression B, tu remarque qu'il n'y aura qu'un cas dont le résultat correspondra à true: le fait que A est vrai ET que B est vrai

    Dés lors, si A est, dés le départ, faux, l'expression sera d'office considérée comme fausse, et l'expression B ne sera jamais évaluée... avec comme résultat que fonctionModifiantI ne sera jamais appelée (et i... jamais modifié)

    Si tu as compris l'optimisation apportée par l'opérateur && (qui est, soit dit en passant similaire pour l'opérateur ||) et que tu es d'accord avec ma table de vérité (et je ne vois pas pourquoi tu ne le serais pas ) tu comprend tous les risques que tu encoure à essayer d'utiliser un effet de bord pour la deuxième expression
    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

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Salut,
    Dés lors, si A est, dés le départ, faux, l'expression sera d'office considérée comme fausse, et l'expression B ne sera jamais évaluée... avec comme résultat que fonctionModifiantI ne sera jamais appelée (et i... jamais modifié)
    oui, et c'est l'effet voulu...
    Je veux executer une fonction seulement si mavariable est à une certaine valeur, et ensuite executer du code si l'appel de ma fonction n'a pas changé ma valeur.

    C'était un exemple, donc mon cas serait plutot celui ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    if(a == 0 && maFonction(&a) && a == 0)
    Dans ce cas le risque éventuel serait que le compilateur ne fasse pas le troisieme test.

  7. #7
    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 pasdeface Voir le message
    oui, et c'est l'effet voulu...
    Je veux executer une fonction seulement si mavariable est à une certaine valeur, et ensuite executer du code si l'appel de ma fonction n'a pas changé ma valeur.

    C'était un exemple, donc mon cas serait plutot celui ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    if(a == 0 && maFonction(&a) && a == 0)
    Dans ce cas le risque éventuel serait que le compilateur ne fasse pas le troisieme test.
    En toute logique, si maFonction renvoie une valeur qui peut être considérée comme fausse (AKA == 0), le troisième test risque effectivement de passer à la trappe...

    Mais, quoi qu'il en soit, n'oublie pas que la première qualité d'un code, avant même de faire ce que l'on attend de lui, c'est d'être facilement lisible et compréhensible, y compris lors qu'une lecture en diagonale...

    L'idéal à mon sens est donc de séparer les différents tests (de toutes manières, cela n'influera nullement sur les performances à l'heure acutelle), sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    if (i==)
    {
        if(maFonction)
       {
           /* retester i éventuellement ici */
       }
    }
    Juste histoire de faire mentir les mauvaises langues qui crient que C est write once read never
    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

  8. #8
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Citation Envoyé par pasdeface Voir le message
    Je veux executer une fonction seulement si mavariable est à une certaine valeur, et ensuite executer du code si l'appel de ma fonction n'a pas changé ma valeur.

    C'était un exemple, donc mon cas serait plutot celui ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    if(a == 0 && maFonction(&a) && a == 0)
    Dans ce cas le risque éventuel serait que le compilateur ne fasse pas le troisieme test.
    Mais "maFonction" retourne quelle valeur ? Car, par exemple, si cette fonction retourne 0, le 3ème test ne sera pas effectué.

  9. #9
    Membre confirmé Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Par défaut
    Citation Envoyé par DaZumba
    Citation:
    Envoyé par sopsag
    C'est même certain !
    Cette condition sera toujours évaluée à FALSE.
    J'en doute. L'important ici, c'est FonctionQuiChangeA(&a).
    Bien sûr !
    Selon la valeur de a, la l'appel à FonctionQuiChangeA se fera ou pas.

    Mais je maintiens que cette condition sera toujours évaluée à FALSE et que donc, le code conditionel qui suit ne sera jamais executé.

    PS : à l'époque de mon post, le code était :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if( a == 0 && FonctionQuiChangeA(&a) && a == 1)
    {
        //du code
    }
    Mais depuis, il a été modifié, et mon commentaire n'a plus de sens...

    Hadrien

  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 sopsag Voir le message
    Bien sûr !
    Selon la valeur de a, la l'appel à FonctionQuiChangeA se fera ou pas.

    Mais je maintiens que cette condition sera toujours évaluée à FALSE et que donc, le code conditionel qui suit ne sera jamais executé.

    PS : à l'époque de mon post, le code était :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if( a == 0 && FonctionQuiChangeA(&a) && a == 1)
    {
        //du code
    }
    Mais depuis, il a été modifié, et mon commentaire n'a plus de sens...

    Hadrien
    Je ne suis pas d'accord avec toi...

    D'abord parce que si tu te pose dans une situation où ta table de vérité donne un résultat vrai, ton expression sera bel et bien évaluée à vrai (si, pour le premier terme, a==0, que FonctionQuiChangeA renvoie vrai et si, après, malgré le changement a==0)

    ensuite, il ne faut pas oublier que c'est une technique qui reste malgré tout souvent utilisée avec les pointeurs:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /* soit une structure proche de */
    struct MaStruct
    {
        type data;
        struct MaStruct* next;
    };
    /* dans une fonction, soit un pointeur de type MaStruct */
    if(ptr && (ptr=ptr->next)!=NULL)
    {
        /* ce qui doit être fait */
    }
    Ce n'est clairement pas le genre de code que je conseille, mais cela fait bel et bien partie des codes qui sont envisageables (et les deux expressions sont évaluées si, à la base, ptr n'est pas nul )

    EDIT Evidemment, si la fonction est sensée modifier a, le test devrait de préférence être au minimum différent
    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
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    J'ai voulu tester ce que le compilo faisait exactement, en sortant du code assembleur. L'ordre des tests est bien respecté.

    Voici le code C :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h> 
    int FonctionQuiChangeA(int *a)
    {
        *a=1;
        return 1;
    }
    int main(void)
    {
        int a;
        srand(time(NULL));
        a=rand()%3;
        if( a == 0 && FonctionQuiChangeA(&a) && a == 1)
        {
            printf("OK...");
        }
     
        getchar();
        return 0;
    }
    Et maintenant le code assembleur généré pour la ligne du "if" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    	.loc 1 14 0
    	mov	eax, DWORD PTR [ebp-8]   <- Correspond à la variable "a"
    	test	eax, eax      <- 1ère condition : On teste si "a" est égal à 0
    	jne	L4         <- On sort du "if" si "a" ne vaut pas 0
    	lea	eax, [ebp-8]
    	push	eax
    LCFI10:
    	call	_FonctionQuiChangeA <- Appelle la fonction
    	add	esp, 4
    	test	eax, eax  <- 2ème condition : On teste si la valeur retournée vaut 0
    	je	L4 <- Si la valeur retournée vaut 0, on sort du "if"
    	mov	eax, DWORD PTR [ebp-8]    <- Correspond à la variable "a"
    	cmp	eax, 1 <- 3ème condition : On compare si "a" vaut 1
    	jne	L4 <- Si "a" n'est pas égal à 1, on sort du "if"
    	.loc 1 16 0 <- On est maintenant dans le bloc "if"
    	sub	esp, 12
    	push	OFFSET FLAT:LC0
    LCFI11:
    	call	_printf
    	add	esp, 16
    L4: <- Sortie du bloc "if"
    	.loc 1 19 0
    Pour résumer :
    1°) La première condition est testée en premier. Si le test échoue, on sort du "if", et les deux autres conditions ne seront pas testées.
    2°) Sinon, on teste la seconde. Si le test échoue, on sort du "if" et la dernière condition ne sera pas testée.
    3°) Sinon, on teste la troisième. Si le test échoue, on sort du "if", et on n'entre pas dans le bloc "if"
    4°) Sinon, le bloc "if" est executé.

  12. #12
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par jeroman Voir le message
    J'ai voulu tester ce que le compilo faisait exactement, en sortant du code assembleur. L'ordre des tests est bien respecté.
    ...
    Pour résumer :
    1°) La première condition est testée en premier. Si le test échoue, on sort du "if", et les deux autres conditions ne seront pas testées.
    2°) Sinon, on teste la seconde. Si le test échoue, on sort du "if" et la dernière condition ne sera pas testée.
    3°) Sinon, on teste la troisième. Si le test échoue, on sort du "if", et on n'entre pas dans le bloc "if"
    4°) Sinon, le bloc "if" est executé.
    Et ça t'étonne ??

    C'est la définition même de la norme...

  13. #13
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Et ça t'étonne ??
    Non, c'était pour montrer la chose "en image".

  14. #14
    Membre confirmé Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Je ne suis pas d'accord avec toi...

    D'abord parce que si tu te pose dans une situation où ta table de vérité donne un résultat vrai, ton expression sera bel et bien évaluée à vrai (si, pour le premier terme, a==0, que FonctionQuiChangeA renvoie vrai et si, après, malgré le changement a==0)
    Et bien moi non plus, je ne suis pas d'accord avec moi !
    Gros beignet que je suis !
    Je n'avais même pas remarqué que la FonctionQuiChangeA pouvait changer a
    C'est effectivement un code un peu pervers mais qui n'est pas dénué de sens...

    Je m'au-temps-pour-moise et présente toutes mes confuses.

    Hadrien

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Plusieur Condition dans REquette UPDATE
    Par ducseb dans le forum Langage SQL
    Réponses: 12
    Dernier message: 11/08/2005, 11h46
  2. [C#] Repeater - Condition dans la structure
    Par stailer dans le forum ASP.NET
    Réponses: 4
    Dernier message: 25/04/2005, 14h54
  3. Enchainer des fonctions dans un onclick d'un bouton
    Par jpg dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 26/10/2004, 16h51
  4. Introduire une condition dans une requete
    Par DeezerD dans le forum Langage SQL
    Réponses: 9
    Dernier message: 12/10/2004, 18h13
  5. Condition dans une requête
    Par fdloisel dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 30/08/2004, 16h55

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