250 votes

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

Je les ai vus à la fois utilisé dans de nombreux morceaux de code C#, et j'aimerais savoir quand utiliser i++ ou ++i (i étant un nombre variable comme int, float, double, etc). Toute personne qui le sait?

516voto

Eric Lippert Points 300275

La réponse typique à cette question, malheureusement déjà posté ici, est que l'on ne l'incrément "avant", le reste de ses opérations et l'autre ne l'incrément "après" d'autres opérations. Bien qu'intuitivement a l'idée de diamètre, qui est de l'instruction sur le visage de celui-ci complètement faux. La séquence des événements dans le temps est extrêmement bien défini en C#, et il n'est absolument pas le cas que le préfixe et le suffixe versions de ++ de faire les choses dans un ordre différent par rapport à d'autres opérations.

Il n'est pas surprenant que vous verrez beaucoup de mauvaises réponses à cette question. Un grand nombre de "teach yourself C#" livres aussi se tromper. En outre, le C# elle est différente de celle du C a-t-il. Beaucoup de gens de raison, comme si C# et C sont dans la même langue; ils ne le sont pas. La conception de l'incrémentation et de décrémentation les opérateurs en C#, à mon avis, évite les défauts de conception de ces opérateurs en C.

Il ya deux questions qui doivent être traitées afin de déterminer ce qu'est exactement le fonctionnement du préfixe et le suffixe ++ en C#. La première question est quel est le résultat? et la deuxième question est de savoir quand les effets secondaires de l'incrément?

Il n'est pas évident que la réponse à une question, mais il est en fait assez simple une fois que vous le voyez. Permettez-moi de préciser pour vous exactement ce que x++ et ++x faire pour une variable x.

Pour le préfixe de la forme:

  • x est évalué à produire de la variable
  • la valeur de la variable est copiée vers un emplacement temporaire
  • la valeur temporaire est incrémenté pour produire une nouvelle valeur (de ne pas écraser le temporaire!)
  • la nouvelle valeur est stockée dans la variable
  • le résultat de l'opération est la nouvelle valeur

Pour postfix forme:

  • x est évalué à produire de la variable
  • la valeur de la variable est copiée vers un emplacement temporaire
  • la valeur temporaire est incrémenté pour produire une nouvelle valeur (de ne pas écraser le temporaire!)
  • la nouvelle valeur est stockée dans la variable
  • le résultat de l'opération est la copie temporaire

Certaines choses sont à remarquer:

Tout d'abord, l'ordre des événements dans le temps, c'est exactement la même dans les deux cas. Encore une fois, il n'est absolument pas le cas, que l' ordre des événements dans le temps les changements entre le préfixe et le suffixe. Il est entièrement faux de dire que l'évaluation qui se passe avant d'autres évaluations ou après d'autres évaluations. Les évaluations se produire dans exactement le même ordre dans les deux cas. La seule différence est la dernière étape - si le résultat est la copie temporaire de la valeur d'origine, ou la nouvelle valeur.

Vous pouvez facilement le démontrer:

static class X 
{
    public static void M(this int x) 
    {
        Console.WriteLine(C.c);
        Console.WriteLine(x);
    }
}
class C
{
    public static int c = 0;
    public static void Main()
    {
        (c++).M();
    }
}

Les gens vont essayer de vous dire que l'accroissement du C.c qui se passe après l'appel à l' X.M(), mais comme vous pouvez le voir lorsque vous exécutez ce programme, il arrive avant l'appel à X.M(). D'abord la valeur courante de C.c est stocké dans un fichier temporaire, puis C.c est incrémenté, et ensuite la valeur de la temporaire est passé de X.M(). Si l'incrément est arrivé après l'appel à l' X.M() alors il faudrait écrire la même valeur à deux reprises, mais il ne le fait pas.

Deuxièmement, c'est pas le cas que la valeur du préfixe version est la nouvelle valeur de x. C'est la valeur qui est stockée dans x. x n'est pas encore lire. x pourrait être volatile et changeante sur un autre thread; la valeur retournée par x++ est pas la valeur actuelle de x, c'est ce que x a été affectée, et qui pourrait être différent.

Il est étonnamment commun pour les gens à être très confus au sujet de la préséance, associativité, et l'ordre dans lequel les effets secondaires sont exécutés, je soupçonne surtout parce qu'il est si confus dans C. C# a été soigneusement conçu pour être le moins perturbant dans tous ces domaines. Pour une analyse complémentaire de ces questions, y compris de plus en plus loin en démontrant la fausseté de l'idée que le préfixe et le suffixe des opérations de "déplacer des choses autour de dans le temps", voir:

http://blogs.msdn.com/b/ericlippert/archive/2009/08/10/precedence-vs-order-redux.aspx

qui a conduit à cette DONC, la question:

int[] arr={0}; int valeur = arr[arr[0]++]; Valeur = 1?

Vous pourriez également être intéressé dans mes précédents articles sur le sujet:

http://blogs.msdn.com/b/ericlippert/archive/2008/05/23/precedence-vs-associativity-vs-order.aspx

et

http://blogs.msdn.com/b/ericlippert/archive/2007/08/14/c-and-the-pit-of-despair.aspx

et un cas intéressant où C ce qui rend difficile de raisonner sur l'exactitude:

http://blogs.msdn.com/b/ericlippert/archive/2005/04/28/bad-recursion-revisited.aspx

Aussi, nous nous heurtons à de semblables questions subtiles lors de l'examen d'autres activités qui ont des effets secondaires, tels que les enchaînés des tâches simples:

http://blogs.msdn.com/b/ericlippert/archive/2010/02/11/chaining-simple-assignments-is-not-so-simple.aspx

Et voici un post intéressant sur les raisons de l'accroissement des opérateurs suite à valeurs dans C# plutôt que dans des variables:

Pourquoi ne puis-je pas faire ++i++ en C-comme langues?

249voto

Kieren Johnstone Points 19499

Bizarrement il ressemble à l'autre des deux réponses n'est pas le préciser, et c'est certainement la peine de dire:


i++ moyen de me parler de la valeur de i, puis incrémentation

++i signifie 'increment i, alors dites-moi la valeur"


Ils sont Pré-incrémentation, la post-incrémentation des opérateurs. Dans les deux cas, la variable est incrémentée, mais si vous prenez de la valeur de deux expressions exactement dans le même cas, le résultat sera différent.

31voto

dcp Points 26928

Si vous avez:

int i = 10;
int x = ++i;

ensuite, x sera 11.

Mais si vous avez:

int i = 10;
int x = i++;

ensuite, x sera 10.

Note Eric points, l'incrément se produit en même temps dans les deux cas, mais c'est ce que la valeur donnée est le résultat qui diffère (merci Eric!).

En général, j'aime utiliser ++i moins qu'il y ait une bonne raison de ne pas. Par exemple, lors de l'écriture d'une boucle, j'aime utiliser:

for (int i = 0; i < 10; ++i) {
}

Ou, si j'ai juste besoin d'incrémenter une variable, j'aime utiliser:

++x;

Normalement, d'une manière ou l'autre n'a pas beaucoup de signification et descend de style de codage, mais si vous êtes en utilisant les opérateurs à l'intérieur d'autres affectations (comme dans mes exemples), il est important d'être conscient des effets secondaires potentiels.

12voto

thelost Points 4691
int i = 0;
Console.WriteLine(i++); // Prints 0. Then value of "i" becomes 1.
Console.WriteLine(--i); // Value of "i" becomes 0. Then prints 0.

Est-ce répondre à votre question ?

8voto

Mike Webb Points 3654

La façon dont l'opérateur fonctionne, c'est qu'il est incrémenté dans le même temps, mais si c'est devant un varable, l'expression d'évaluer avec le incrémenté/décrémenté variable:

int x = 0;   //x is 0
int y = ++x; //x is 1 and y is 1

Si c'est après la variable dans l'instruction en cours seront exécutés avec la variable d'origine, comme si elle n'avait pas encore été incrémenté/décrémenté:

int x = 0;   //x is 0
int y = x++; //'y = x' is evaluated with x=0, but x is still incremented. So, x is 1, but y is 0

Je suis d'accord avec dcp dans l'utilisation de pré-incrémentation/décrémentation (++x) sauf si nécessaire. Vraiment la seule fois que j'utilise la post-incrémentation/décrémentation est dans les boucles while ou des boucles de la sorte. Ces boucles sont les mêmes:

while (x < 5)  //evaluates conditional statement
{
    //some code
    ++x;       //increments x
}

ou

while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
    //some code
}

Vous pouvez aussi le faire lors de l'indexation des tableaux et tel:

int i = 0;
int[] MyArray = new int[2];
MyArray[i++] = 1234; //sets array at index 0 to '1234' and i is incremented
MyArray[i] = 5678;   //sets array at index 1 to '5678'
int temp = MyArray[--i]; //temp is 1234 (becasue of pre-decrement);

Etc, etc...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X