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?
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
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
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.
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.
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.