web-dev-qa-db-fra.com

Incrément avant et après en C #

Je suis un peu confus quant à la façon dont le compilateur C # gère les incréments et les décréments avant et après.

Lorsque je code ce qui suit:

int x = 4;
x = x++ + ++x;

x aura ensuite la valeur 10. Je pense que c'est parce que la pré-incrémentation définit x sur 5, ce qui en fait 5+5 qui correspond à 10. Ensuite, le post-incrément met à jour x en 6, mais cette valeur ne sera pas utilisée car alors 10 sera affecté à x.

Mais quand je code:

int x = 4;
x = x-- - --x;

alors x sera 2 ensuite. Quelqu'un peut-il expliquer pourquoi c'est le cas?

61
Schweder

x-- sera 4, mais sera 3 au moment de --x, il finira par être 2, alors vous aurez

x = 4 - 2

btw, votre premier cas sera x = 4 + 6

Voici un petit exemple qui imprimera les valeurs de chaque partie, peut-être que vous comprendrez mieux ainsi:

static void Main(string[] args)
{
    int x = 4;
    Console.WriteLine("x++: {0}", x++); //after this statement x = 5
    Console.WriteLine("++x: {0}", ++x); 

    int y = 4;
    Console.WriteLine("y--: {0}", y--); //after this statement y = 3
    Console.WriteLine("--y: {0}", --y);

    Console.ReadKey();
}

cela imprime

x++: 4
++x: 6
y--: 4
--y: 2
50
Sebastian Piu

Jetons un œil à l'IL généré à partir de cette déclaration

IL_0002:  ldloc.0     

Charge la valeur de x sur la pile. Pile => (4)

IL_0003:  dup         

Duplique l'élément le plus haut de la pile. Pile => (4, 4)

IL_0004:  ldc.i4.1    

Poussez 1 sur la pile. Pile => (1, 4, 4)

IL_0005:  sub         

Soustrayez les deux premières valeurs et envoyez le résultat sur la pile. Pile => (3, 4)

IL_0006:  stloc.0     

Stockez la valeur la plus élevée de la pile sur x. Pile => (4)

IL_0007:  ldloc.0     

Chargez la valeur de x dans la pile. Pile => (3, 4)

IL_0008:  ldc.i4.1    

Chargez la valeur 1 sur la pile. Pile => (1, 3, 4)

IL_0009:  sub         

Soustrayez les deux. Pile => (2, 4)

IL_000A:  dup         

Dupliquez la valeur supérieure => (2, 2, 4)

IL_000B:  stloc.0     

Stockez la valeur supérieure à x. Pile => (2, 4)

IL_000C:  sub      

Soustrayez les deux premières valeurs. Pile => (2)

IL_000D:  stloc.0  

Enregistrez cette valeur dans x. x == 2

18
Mongus Pong

De votre commentaire:

Je pensais que les post-et pré-incréments sont exécutés après/avant l'évaluation de la ligne de code complète - mais ils sont exécutés après/avant l'évaluation de chaque élément de l'expression.

Votre malentendu est extrêmement courant. Notez que dans certains langages, comme C, il n'est pas spécifié lorsque l'effet secondaire devient visible et il est donc légal, mais pas obligatoire, que votre déclaration soit vraie en C.

Ce n'est pas le cas en C #; en C # les effets secondaires du code du côté gauche d'une expression sont toujours observés avant que le code du côté droit ne s'exécute (à partir d'un seul thread; dans scénarios multithread tous les paris sont désactivés.)

Pour une explication plus détaillée de ce que font les opérateurs d'incrémentation en C #, voir:

Quelle est la différence entre i ++ et ++ i?

Il existe de nombreux liens supplémentaires vers des articles que j'ai écrits sur ce sujet souvent mal compris.

9
Eric Lippert

La chose la plus intéressante à laquelle vous obtiendrez une réponse complètement différente avec le compilateur C++. Net.

int x = 4;
x = x++ + ++x; // x = 11
x = 4;
x = x-- - --x; // x = -1

Bien sûr, la différence de résultats est déterminée par différents sémantique - cela semble normal. Mais malgré la compréhension, le fait que deux compilateurs .net ne se comportent pas de manière similaire pour de telles choses de base me déroute aussi.

6
Shymep

Dans cet exemple,

int x = 4;
x = x++ + ++x;

vous pouvez le casser comme:

x = 4++; which is = 5
x = 4 + ++5; which is 4 + 6
x = 10

De même,

int x = 4;
x = x-- - --x;

Ici,

x = 4--; which is = 3
x = 4 - --3; which is 4 - 2
x = 2

En termes simples, vous pouvez dire, remplacer la valeur actuelle de x, mais pour chaque ++ ou - ajouter/soustraire une valeur de x.

2
Azhar Khorasany