web-dev-qa-db-fra.com

Pourquoi «if (i ++ && (i == 1))» est-il faux lorsque i est un entier contenant la valeur 1?

{
    int i = 1;
    if (i++ && (i == 1))
        printf("Yes\n");
    else
        printf("No\n");
}

Selon ma compréhension, dans la condition if, d'abord l'expression (i==1) sera évalué, ce qui devrait renvoyer 1, puis il est logiquement andé avec 1 qui est la valeur de i, donc l'expression doit retourner 1 && 1 == 1, mais la partie else est exécutée.

Quelqu'un peut-il expliquer pourquoi la partie else est exécutée?

44
Tahir Sanglikar

Non. En C, il y a un point de séquence entre l'évaluation du LHS du && l'opérateur et l'évaluation de l'ERS, et l'incrémentation doit avoir lieu et être terminée avant l'évaluation de l'ERS. Alors le i++ (équivalent à i++ != 0) est exécuté et l'incrémentation est terminée (et l'expression prend la valeur true), donc au moment où le RHS est évalué, i == 2 et donc l'expression globale est fausse et vous obtenez 'Non' imprimé. Si le LHS du && opérateur évalué à false (0), le RHS ne serait pas évalué en raison de la propriété de court-circuit du && opérateur.

Seuls quelques opérateurs ont la propriété d'avoir un point de séquence entre l'évaluation du LHS et du RHS: &&, ||, et , (en tant qu'opérateur, pas en tant que séparateur dans une liste d'arguments) - et il y a ? : aussi, qui n'est pas un opérateur binaire mais qui a un point de séquence après l'évaluation de la condition et avant l'expression après le ? ou l'expression après le : est évalué (dont l'un ou l'autre, mais pas les deux, est toujours évalué).

Le && et || les opérateurs sont les seuls opérateurs à posséder la propriété "court-circuit". Le RHS de && n'est évalué que si le LHS donne la valeur true; l'ERS de || n'est évalué que si le LHS est faux.


Clarification sur les points de séquence

Iwillnotexist Idonotexist correctement affirmé :

La norme C11 n'a pas supprimé les points de séquence, seule la norme C++ 11 l'a fait.

C++ 11 (ISO/IEC 14882: 2011) dit:

1.9 Exécution du programme

¶13 Séquencé avant est une relation asymétrique, transitive, par paire entre les évaluations exécutées par un seul thread (1.10), qui induit un ordre partiel parmi ces évaluations. Pour deux évaluations [~ # ~] a [~ # ~] et [~ # ~] b [~ # ~], si [~ # ~] a [~ # ~] est séquencé avant [~ # ~] b [~ # ~], puis l'exécution de [ ~ # ~] a [~ # ~] doit précéder l'exécution de [~ # ~] b [~ # ~]. Si [~ # ~] a [~ # ~] n'est pas séquencé avant [~ # ~] b [~ # ~] et [~ # ~] b [~ # ~] n'est pas séquencé avant [~ # ~] a [~ # ~], puis [~ # ~ ] a [~ # ~] et [~ # ~] b [~ # ~] sont sans séquence. [ Remarque: L'exécution des évaluations non séquencées peut se chevaucher. - note de fin] Évaluations [~ # ~] a [~ # ~] et [~ # ~] b [~ # ~] sont séquencés de façon indéterminée lorsque soit [~ # ~] un [~ # ~] est séquencé avant [~ # ~ ] b [~ # ~] ou [~ # ~] b [~ # ~] est séquencé avant [~ # ~] a [~ # ~ ], mais il n'est pas précisé lequel. [ Remarque: Les évaluations séquencées de façon indéterminée ne peuvent pas se chevaucher, mais l'une ou l'autre pourrait être exécutée en premier. - note de fin]

Le terme "point de séquence" n'apparaît pas du tout dans C++ 11 (la seule correspondance proche est "pointeur de séquence").

C11 (ISO/IEC 9899: 2011) dit:

5.1.2.3 Exécution du programme

¶3 Séquencé avant est une relation asymétrique, transitive, par paire entre les évaluations exécutées par un seul thread, qui induit un ordre partiel parmi ces évaluations. Pour deux évaluations [~ # ~] a [~ # ~] et [~ # ~] b [~ # ~], si [~ # ~] a [~ # ~] est séquencé avant [~ # ~] b [~ # ~], puis l'exécution de [ ~ # ~] a [~ # ~] doit précéder l'exécution de [~ # ~] b [~ # ~]. (Inversement, si [~ # ~] a [~ # ~] est séquencé avant [~ # ~] b [~ # ~], alors = [~ # ~] b [~ # ~] est séquencé après [~ # ~] a [~ # ~] =.) Si [~ # ~] a [~ # ~] n'est pas séquencé avant ou après [~ # ~] b [~ # ~] , alors [~ # ~] a [~ # ~] et [~ # ~] b [~ # ~] sont non séquencés. Les évaluations [~ # ~] a [~ # ~] et [~ # ~] b [~ # ~] sont séquencées de façon indéterminée lorsque [~ # ~] a [~ # ~] est séquencé avant ou après [~ # ~] b [~ # ~] =, mais il n'est pas précisé lequel.13) La présence d'un point de séquence entre l'évaluation des expressions [~ # ~] a [~ # ~] et [~ # ~] b [~ # ~] implique que chaque calcul de valeur et effet secondaire associé à [~ # ~] a [~ # ~] est séquencé avant chaque calcul de valeur et effet secondaire associé à [~ # ~] b [~ # ~]. (Un résumé des points de séquence est donné à l'annexe C.)

13) Les exécutions d'évaluations non séquencées peuvent s'entrelacer. Les évaluations séquencées de façon indéterminée ne peuvent pas s'entrelacer mais peuvent être exécutées dans n'importe quel ordre.

Ainsi, C11 conserve les points de séquence, mais ajoute le "séquencé avant" et les termes associés en utilisant essentiellement la même terminologie que C++ 11.

92
Jonathan Leffler

Ici, une explication simple

enter image description here

et c'est pourquoi cette condition devient "fausse"

40
Sruit A.Suk

Quand && est utilisé dans une expression, ses arguments sont garantis évalués de gauche à droite. Ainsi, i aura la valeur de 2 quand (i==1) est évalué. Par conséquent, l'expression est fausse et la partie else sera exécutée.

Cependant, notez par souci d'exhaustivité que si l'argument gauche est évalué à faux ou à 0, alors l'argument droit n'est pas évalué du tout.

28
user3821934

Je pense que 11 = 1 et 10 = 0 est clair pour vous. La réponse de Michael L me semble bonne, mais je vais quand même essayer de développer un peu. Voici le lien qui fournit la liste de priorité des opérateurs:

http://www.difranco.net/compsci/C_Operator_Precedence_Table.htm

Si vous visitez ce lien et référez-vous à ce tableau, vous découvrirez qu'il y a de l'associativité de gauche à droite. la vérification est effectuée, nous pouvons le vérifier en écrivant le code comme celui ci-dessous:

Ce code explique que i = 2 lorsque le flux d'exécution atteint i == 1 partie.

#include <stdio.h>
int main() {

    int i = 1;
    if (i++ && (printf("%d\n",i)))
        printf("Yes\n");
    else
        printf("No\n");
    return 0;
}

La sortie est donc:

2

Oui

Donc 2 == 1 se révèle faux et finalement la réponse donne une sensation surprenante !!! Le support du côté droit donne 0 et le côté gauche 1 donc 10 = 0. Je pense que c'est assez juste pour comprendre.

1
codecracker

Vous êtes confus car dans la boucle, l'instruction i ++ est utilisée pour l'incrémentation. par exemple.

for (i=0;i<1;i++)

Dans le programme de boucle ci-dessus, i obtiendra d'abord la valeur initiale et vérifiera la condition. La condition if est vraie, donc elle incrémente i et évalue i à l'ancienne valeur pour le corps de la boucle mais en dehors du corps de la boucle, elle a une nouvelle valeur - 1.

Dans votre question, vous utilisez if et l'étendue de l'ancienne valeur de i se terminera quand il rencontrera un opérateur logique, il obtiendra automatiquement une nouvelle valeur et augmentera à 2 donc la condition renvoie faux.

0
Muhammad Nasir