Ordre d'évaluation dans l'opérateur ternaire avec incréments

2020-06-02 c conditional-operator
#define MAX(a,b) ((a)>(b) ? (a) : (b))
   int main(void) {
   int a=2;
   int b=3;

   int c = MAX(a++,b++); // c=((a++)>(b++) ? (a++) : (b++));
   printf("\na= %d", a);// a=3
   printf("\nb= %d", b);//b=5
   printf("\nc= %d", c);//c=4

   a=3;
   b=2;
   cc = MAX(a++,b++); // c=((a++)>(b++) ? (a++) : (b++));

   printf("\na= %d", a); // a=5
   printf("\nb= %d", b); //b=3
   printf("\nc= %d", c); //c=4

return 0;
}

Je voudrais savoir pourquoi c n'est pas évalué à 5.

Il me semble que l'ordre d'évaluation devrait être:

  1. Commencez par a et être incrémenté dans (a++)>(b++)
  2. Si par exemple le premier est supérieur, l'opérateur ternaire c=((a++)>(b++) ? (a++) : (b++)) , va à (a++) , donc a incrémente à nouveau.
  3. Le résultat de l'expression ternaire, qui est un incrément de deux fois, devrait être assigné à c , alors c devrait avoir la plus grande valeur incrémenté deux fois, soit 5. Cependant, je reçois 4. Je soupçonne le le deuxième incrément de plus grande valeur se produit à la fin, mais je ne peux pas expliquer pourquoi, puisque les parenthèses semblent indiquer que le mission vient à la fin.

Une idée?

Answers

Considérons par exemple cette déclaration

int c = MAX(a++,b++);

après la macro substitution, il y aura

int c = (( a++) >( b++ ) ? (a++) : (b++));

Les variables a et b sont initialisées comme

int a=2;
int b=3;

Comme a est inférieur à b la troisième expression (b++) sera évaluée comme résultat de l'opérateur conditionnel. Dans la première expression ( a++) >( b++ ) a et b ont été incrémentés. Il y a un point de séquence après l'évaluation de la première expression.

Ainsi, a sera défini sur 3 , b sera défini sur 4 .

Comme il a déjà été dit, la valeur de l'opérateur conditionnel est la valeur de la troisième expression (b++) où est utilisé le post-incrément. La valeur de l'opérateur post-incrémentation est la valeur de son opérande avant incrémentation.

De la norme C (6.5.2.4 Opérateurs d'incrémentation et de décrémentation Postfix)

2 Le résultat de l'opérateur postfix ++ est la valeur de opérande. Comme effet secondaire, la valeur de l'objet opérande est incrémenté (c'est-à-dire que la valeur 1 du type approprié est ajoutée à il).

La valeur de l'opérateur conditionnel est donc 4 . Cette valeur sera affectée à la variable c . Mais comme effet secondaire, la valeur de b sera incrémentée.

Ainsi, après cette déclaration, a sera égal à 3 , b sera égal à 5 et c sera égal à 4 .

Pour plus de clarté, cette déclaration

int c = (( a++) >( b++ ) ? (a++) : (b++));

en fait, peut être réécrit de manière logiquement équivalente.

int result = a > b;
++a;
++b;

int c;

if ( result != 0 )
{
    c = a++;
}
else
{
    c = b++;
}

L'opérateur postfix ++ a un résultat et un effet secondaire . Le résultat de a++ est la valeur de a avant l'incrément - donnée

int a = 1;
int x = a++;

la valeur de x sera 1 et la valeur de a sera 2. Notez que l'effet secondaire de l'ajout de 1 à a ne doit pas être appliqué immédiatement après l'évaluation - il doit seulement être appliqué avant le prochain point de séquence.

Donc, en regardant

((a++) > (b++)) ? (a++) : (b++)

L'opérateur ?: Force l'évaluation de gauche à droite, donc la première chose qui se produit est que (a++) > (b++) est évalué 1 . Puisque a est initialement 2 et b est initialement 3 , le résultat de l'expression est faux ( 0 ). Le ? L'opérateur introduit un point de séquence, donc les effets secondaires sur a et b sont appliqués et a est maintenant 3 et b est maintenant 4 .

Puisque le résultat de l'expression de condition était 0 , nous évaluons b++ . Même chose, le résultat de l'expression est la valeur actuelle de b ( 4 ), et cette valeur est affectée à c . L'effet secondaire de b est appliqué à un moment donné, et au moment où tout est terminé, a est 3 , b est 5 et c est 4 .


  1. Bien que dans cette expression, a++ ou un b++ peut être évalué en premier, car l'opérateur > ne force pas l'évaluation de gauche à droite.

Pour a ++, c'est équivalent à dire

int temp = a;
a = a + 1;
return temp;

donc dans le cas de a = 2, b = 3, nous pouvons aller à la condition (a ++)> (b ++) et nous pouvons avoir une réécriture comme

int temp1 = a;
a = a + 1;
return temp1;

et b réécrit comme

int temp2 = b;
b = b + 1;
return temp2;

maintenant, comme il ne s'agit que d'une instruction conditionnelle, nous évaluons vraiment les anciennes valeurs de a et b avant l'incrément qui est temp1 = 2 et temp2 = 3 tandis qu'en même temps les valeurs a et b ont changé a = 3, b = 4. Puisque temp1 <temp2 de l'ancienne valeur, nous allons à la fausse clause de l'opérateur ternaire (b ++) et faisons la même chose que nous l'avons fait avant

int temp3 = b;
b = b + 1;
return temp3;

alors maintenant b est 5 tandis que le temp3 retourné est la valeur précédente de b qui est 4. J'espère que cela aide!

Related