Je les ai vus tous deux utilisés dans de nombreux morceaux de code C #, et je voudrais savoir quand utiliser i++
ou ++i
( i
étant une variable de nombre comme int
, float
, double
, etc.). Quelqu'un qui sait cela?
Je les ai vus tous deux utilisés dans de nombreux morceaux de code C #, et je voudrais savoir quand utiliser i++
ou ++i
( i
étant une variable de nombre comme int
, float
, double
, etc.). Quelqu'un qui sait cela?
Réponses:
Curieusement, il semble que les deux autres réponses ne l'expliquent pas, et cela vaut vraiment la peine de dire:
i++
signifie "dites-moi la valeur de i
, puis incrémentez"
++i
signifie «incrémenter i
, puis dites-moi la valeur»
Ce sont des opérateurs pré-incrément, post-incrément. Dans les deux cas, la variable est incrémentée , mais si vous deviez prendre la valeur des deux expressions exactement dans les mêmes cas, le résultat sera différent.
La réponse typique à cette question, malheureusement déjà affichée ici, est que l'un fait l'incrémentation "avant" les opérations restantes et l'autre fait l'incrémentation "après" les opérations restantes. Bien que cela fasse intuitivement passer l'idée, cette déclaration est à première vue complètement fausse . La séquence d'événements dans le temps est extrêmement bien définie en C #, et ce n'est absolument pas vrai que les versions préfixe (++ var) et postfix (var ++) de ++ fassent les choses dans un ordre différent par rapport aux autres opérations.
Il n'est pas surprenant que vous verrez beaucoup de mauvaises réponses à cette question. Un grand nombre de livres «apprenez-vous en C #» se trompent également. De plus, la façon dont C # le fait est différente de la façon dont C le fait. Beaucoup de gens pensent que C # et C sont le même langage; ils ne sont pas. À mon avis, la conception des opérateurs d'incrémentation et de décrémentation en C # évite les défauts de conception de ces opérateurs en C.
Il y a deux questions auxquelles il faut répondre pour déterminer exactement le fonctionnement du préfixe et du suffixe ++ en C #. La première question est quel est le résultat? et la deuxième question est quand se produit l'effet secondaire de l'augmentation?
La réponse à l'une ou l'autre des questions n'est pas évidente, mais elle est en fait assez simple une fois que vous la voyez. Permettez-moi de vous expliquer précisément ce que x ++ et ++ x font pour une variable x.
Pour le préfixe (++ x):
Pour le formulaire postfix (x ++):
Quelques points à noter:
Premièrement, l'ordre des événements dans le temps est exactement le même dans les deux cas . Encore une fois, il n'est absolument pas vrai que l' ordre des événements dans le temps change entre le préfixe et le postfix. Il est tout à fait faux de dire que l'évaluation a lieu avant d'autres évaluations ou après d'autres évaluations. Les évaluations se déroulent exactement dans le même ordre dans les deux cas, comme vous pouvez le voir aux étapes 1 à 4 étant identiques. La seule différence est la dernière étape - que le résultat soit la valeur de la valeur temporaire ou de la nouvelle valeur incrémentée.
Vous pouvez facilement le démontrer avec une simple application console C #:
public class Application
{
public static int currentValue = 0;
public static void Main()
{
Console.WriteLine("Test 1: ++x");
(++currentValue).TestMethod();
Console.WriteLine("\nTest 2: x++");
(currentValue++).TestMethod();
Console.WriteLine("\nTest 3: ++x");
(++currentValue).TestMethod();
Console.ReadKey();
}
}
public static class ExtensionMethods
{
public static void TestMethod(this int passedInValue)
{
Console.WriteLine("Current:{0} Passed-in:{1}",
Application.currentValue,
passedInValue);
}
}
Voici les résultats...
Test 1: ++x
Current:1 Passed-in:1
Test 2: x++
Current:2 Passed-in:1
Test 3: ++x
Current:3 Passed-in:3
Dans le premier test, vous pouvez voir que les deux currentValue
et ce qui a été transmis auTestMethod()
extension affichent la même valeur, comme prévu.
Cependant, dans le second cas, les gens essaieront de vous dire que l'incrémentation currentValue
se produit après l'appel à TestMethod()
, mais comme vous pouvez le voir sur les résultats, cela se produit avant l'appel, comme indiqué par le résultat 'Current: 2'.
Dans ce cas, la valeur de currentValue
est d'abord stockée dans un fichier temporaire. Ensuite, une version incrémentée de cette valeur est stockée dans currentValue
mais sans toucher au temporaire qui stocke toujours la valeur d'origine. Enfin, ce temporaire est transmis à TestMethod()
. Si l'incrément s'est produit après l'appel à, TestMethod()
il écrirait deux fois la même valeur non incrémentée, mais ce n'est pas le cas.
Il est important de noter que la valeur renvoyée par les opérations
currentValue++
et++currentValue
est basée sur la valeur temporaire et non sur la valeur réelle stockée dans la variable au moment où l'une des opérations se termine.Rappelez-vous dans l'ordre des opérations ci-dessus, les deux premières étapes copient la valeur alors actuelle de la variable dans le temporaire. C'est ce qui est utilisé pour calculer la valeur de retour; dans le cas de la version préfixe, c'est cette valeur temporaire incrémentée tandis que dans le cas de la version suffixe, c'est cette valeur directement / non incrémentée. La variable elle-même n'est pas relue après le stockage initial dans le temporaire.
En termes plus simples, la version postfixe renvoie la valeur qui a été lue à partir de la variable (c'est-à-dire la valeur du temporaire) tandis que la version du préfixe renvoie la valeur qui a été réécrite dans la variable (c'est-à-dire la valeur incrémentée du temporaire). Ni retourner la valeur de la variable.
Ceci est important à comprendre car la variable elle-même peut être volatile et avoir changé sur un autre thread, ce qui signifie que la valeur de retour de ces opérations peut différer de la valeur actuelle stockée dans la variable.
Il est étonnamment courant que les gens soient très confus au sujet de la priorité, de l'associativité et de l'ordre dans lequel les effets secondaires sont exécutés, je soupçonne principalement parce que c'est tellement déroutant en C.C # a été soigneusement conçu pour être moins déroutant à tous ces égards. Pour une analyse supplémentaire de ces problèmes, y compris moi démontrant davantage la fausseté de l'idée que les opérations de préfixe et de postfix "déplacent les choses dans le temps", voir:
https://ericlippert.com/2009/08/10/precedence-vs-order-redux/
qui a conduit à cette question SO:
int [] arr = {0}; valeur int = arr [arr [0] ++]; Valeur = 1?
Vous pourriez également être intéressé par mes précédents articles sur le sujet:
https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/
et
https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/
et un cas intéressant où C rend difficile de raisonner sur l'exactitude:
https://docs.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited
En outre, nous rencontrons des problèmes subtils similaires lorsque nous considérons d'autres opérations qui ont des effets secondaires, telles que des affectations simples chaînées:
https://docs.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple
Et voici un article intéressant sur la raison pour laquelle les opérateurs d'incrémentation produisent des valeurs en C # plutôt qu'en variables :
Pourquoi ne puis-je pas faire ++ i ++ dans des langages de type C?
i++
ou ++i
sont utilisés dans du code, les choses qui se passent en arrière-plan ne sont que cela; en arrière-plan . J'écris C # pour grimper à des niveaux d'abstraction supérieurs à ce qui se passe à ce niveau, donc si cela compte vraiment pour votre code C #, vous êtes peut-être déjà dans le mauvais langage.
i++;
) est dans for (int i = 0; i < x; i++)
... Et je suis très très heureux de ça! (et je n'utilise jamais l'opérateur de préfixe). Si je dois écrire quelque chose qui nécessitera un programmeur senior 2 minutes pour déchiffrer ... Eh bien ... Il vaut mieux écrire une autre ligne de code ou introduire une variable temporaire :-) Je pense que votre "article" (j'ai gagné n'appelle pas ça "répondre") confirme mon choix :-)
Si tu as:
int i = 10;
int x = ++i;
puis x
sera 11
.
Mais si vous avez:
int i = 10;
int x = i++;
puis x
sera 10
.
Notez qu'Eric le fait remarquer, l'incrément se produit en même temps dans les deux cas, mais c'est la valeur donnée comme 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 le faire. 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 d'une autre, cela n'a pas beaucoup d'importance et se résume au style de codage, mais si vous utilisez les opérateurs dans d'autres affectations (comme dans mes exemples originaux), il est important d'être conscient des effets secondaires potentiels.
i
le nom de variable plutôt quevar
comme c'est un mot clé C #.
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 que cela répond à votre question ?
La façon dont l'opérateur fonctionne est qu'il est incrémenté en même temps, mais s'il est avant une variable, l'expression sera évaluée avec la variable incrémentée / décrémentée:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
Si c'est après la variable, l'instruction courante sera exécutée avec la variable d'origine, comme si elle n'avait pas encore été incrémentée / décrémentée:
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 pour utiliser la pré-incrémentation / décrémentation (++ x) sauf si nécessaire. Vraiment, la seule fois où j'utilise le post-incrément / décrément, c'est pendant que des boucles ou des boucles de ce type. 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 également le faire lors de l'indexation des tableaux et autres:
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...
Juste pour mémoire, en C ++, si vous pouvez utiliser soit (c'est-à-dire) vous ne vous souciez pas de l'ordre des opérations (vous voulez juste incrémenter ou décrémenter et l'utiliser plus tard), l'opérateur de préfixe est plus efficace car il ne le fait pas doivent créer une copie temporaire de l'objet. Malheureusement, la plupart des gens utilisent posfix (var ++) au lieu du préfixe (++ var), simplement parce que c'est ce que nous avons appris au départ. (On m'a posé des questions à ce sujet dans une interview). Je ne sais pas si cela est vrai en C #, mais je suppose que ce serait le cas.