Comment fonctionnent les opérations Prefix (++x) et Postfix (x++)?

est-ce que quelqu'un peut me dire comment les opérateurs de préfixe / postfix fonctionnent vraiment? J'ai beaucoup cherché sur Internet, mais je n'ai rien trouvé.

de ce que je peux dire prefex premiers incréments, puis fait l'opération et puis assigne.

Postfix effectuerait d'abord l'opération, puis assignerait et incrémenterait.

mais j'ai un petit problème avec mon code:

int x, y;
x = 1;
y = x + x++; // (After operation y = 2)(x=2)

Cependant, quand je fais:

y = x++ + x; // (After operation y = 3)(x=2)

Je ne sais pas pourquoi ces opérations seraient différentes. J'ai deux questions:

  • Pourriez-vous expliquer la différence?

  • Comment cela s'applique à l'autre opérateur Préfixe?

25
demandé sur Jeroen Vannevel 2011-10-18 22:53:10

7 réponses

  • dans C# les opérandes de + sont evaulées dans l'ordre de gauche à droite.
  • en C et c++ l'ordre d'évaluation pour les opérandes de + n'est pas précisé.

Pour C# vos exemples de travail comme suit:

 y = x + x++;
     ^ x is 1
         ^ x is increased to 2, but the postfix increment returns the old value (1)
 y = 2

 y = x++ + x;
     ^ x becomes 2, but postfix increment returns the old value (1)
           ^ x is now 2 here
 y = 3
26
répondu Mark Byers 2011-10-18 19:23:37

cette question est posée à juste titre. Soyez averti que chaque fois que quelqu'un pose cette question un grand nombre de personnes poste des réponses incorrectes. Beaucoup de gens ont des idées fausses sur la façon dont ces opérateurs fonctionnent, y compris les gens qui écrivent des livres de programmation et enseignent ainsi à d'autres personnes des mensonges. Lire les autres réponses ici très soigneusement.

pour une analyse correcte du comportement C#, voir:

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

pour C++ tout comportement est un comportement correct, dans les cas où vous observez un effet secondaire. C++ ne définit pas quand l'effet secondaire de l'incrément est visible. deux compilateurs peuvent le faire différemment.

une bonne règle à suivre est de ne pas compter sur l'ordre dans lequel les effets secondaires se produisent dans tout langue, mais certainement ne pas compter sur en C++, car il n'est pas fiable.

pour examiner votre cas spécifique:

int x, y;     
x = 1;     
y = x + x++; 

vous déclarez que x et y sont 2. C'est correct dans C#. Dans C# le comportement correct est:

  • évaluer les y comme une variable
  • evaluer x comme valeur -- il est 1
  • évalue x++ comme valeur. Cela évalue x comme une variable, puis prend sa valeur originale qui est 1, puis augmente cette valeur, qui est 2, puis attribue 2 à x et donne la valeur originale, qui est 1.
  • evaluer 1 + 1, qui est 2
  • attribuer 2 à Y.

Si x et y sont 2 en C#.

C++ peut faire la même chose, mais il est permis d'évaluer l'ajout de droite à gauche. C'est-à-dire qu'il est permis de faire:

  • évaluer x++ comme une valeur. Cela évalue x comme une variable, puis prend sa valeur originale qui est 1, puis incrémente cette valeur, qui est 2, puis assigne 2 à x et donne alors la valeur originale, qui est 1.
  • evaluer x comme valeur -- il est 2
  • evaluer 1 + 2, qui est 3
  • évaluer les y comme une variable
  • assignez 3 à Y.

C++ est également autorisé à faire ceci:

  • évaluer x++ comme une valeur. Cela évalue x comme une variable, puis prend sa valeur originale qui est 1, Puis augmente cette valeur, qui est 2 ... l'étape qui manque ici ... et il en résulte la valeur originale, qui est 1.
  • evaluer x comme valeur -- il est 1
  • evaluer 1 + 1, qui est 2
  • assigne 2 à x -- l'étape qui manquait auparavant.
  • évaluer y comme variable
  • attribuer 2 à Y.

ainsi en C++, vous pouvez obtenir y comme 3 ou 2, selon le caprice de l'auteur du compilateur. En C#, vous obtenez toujours que y est de 2. En C++, l'affectation de l'incrément peut se produire à tout moment , aussi longtemps que cela se produit. Dans C#, l'attribution de l'augmentation doit se produire après la valeur incrémentée est calculée et avant la valeur originale est utilisée. (Lorsque observé à partir du thread d'exécution; si vous essayez d'observer ce truc à partir d'un autre thread ou threads, tous les paris sont éteints.)

dans votre deuxième exemple:

y = x++ + x; 

En C# le comportement requis est:

  • évaluer les y comme une variable
  • évalue x++ comme valeur. Cela évalue x comme une variable, puis prend sa valeur originale qui est 1, puis incrémente cette valeur, qui est 2, puis assigne 2 à x et donne alors la valeur originale, qui est 1.
  • evaluer x comme valeur -- il est 2
  • evaluer 1 + 2, qui est 3
  • assignez 3 à Y.

donc la bonne réponse dans C# est que y est 3 et x est 2.

encore une fois, C++ peut faire ces étapes dans n'importe quel ordre. C++ est autorisé à faire:

  • évaluer x comme une valeur -- il est 1
  • évalue x++ comme valeur. Cela évalue x comme une variable, puis prend sa valeur originale qui est 1, puis incrémente cette valeur, qui est 2, puis assigne 2 à x et donne alors la valeur originale, qui est 1.
  • evaluer 1 + 1, qui est 2
  • évaluer les y comme une variable
  • attribuer 2 à Y.

encore une fois, en C++ la bonne réponse est que y est 2 ou 3, selon le coup de tête de le compilateur de l'écrivain. Dans C# la bonne réponse est que y est 3.

57
répondu Eric Lippert 2017-05-23 12:25:27

dans les deux cas, l'incrément a été appliqué après l'utilisation du x. Dans la première, il a été évalué comme suit: y = 1 + 1 (incrémenté à 2)

dans le deuxième

y = 1 (incrémenté à 2) + 2.

c'est pour ça que tu as des réponses différentes.

6
répondu Lou 2011-10-18 18:57:15

en C et C++:

La sortie est non spécifié .

Référence-C++03 Standard:

Section 5: Expressions, Para 4:

sauf indication contraire [par exemple règles spéciales pour & & & et||], l'ordre d'évaluation des opérandes des opérateurs individuels et des sous-expressions des expressions individuelles, et l'ordre dans lequel les effets secondaires prennent place, est Indéterminé.

En C99 La Section 6.5.

"Le groupement d'opérateurs et d'opérandes est indiqué par la syntaxe.72) sauf indication contraire (pour la fonction-Appel (), &&, ||, ?: et la virgule opérateurs), l'ordre d'évaluation des sous-expressions et l'ordre dans lequel les effets secondaires sont à la fois non spécifié."

6
répondu Alok Save 2011-10-18 19:01:46

les expressions x++ et ++x ont à la fois un" résultat (ou valeur) et un "effet secondaire .

si nous limitons notre discussion aux opérandes de type intégral, le" résultat de x++ est quelle que soit la valeur actuelle de x . Le effet secondaire est d'augmenter x par 1. Ainsi, compte tenu du code

x = 0;
y = x++;

le résultat sera x = = 1 et y = = 0 (en supposant que x et y sont des types intégraux).

pour ++x , le "résultat est 1 plus la valeur actuelle de x . Le effet secondaire est d'augmenter x par 1. Ainsi, compte tenu du code

x = 0;
y = ++x;

le résultat sera x == y == 1.

ce qui distingue C et c++ de C#, c'est quand les opérandes sont évaluées et quand les effets secondaires sont appliqués. C# garantit que les opérandes d'une expression sont toujours évaluées de gauche à droite. C et c++ Ne garantissent qu'une évaluation de gauche à droite && , || , ?: , virgule, Et Fonction-Appel () opérateurs-pour tous les autres opérateurs, l'ordre dans lequel les opérandes sont évaluées est non spécifié .

de même, en C#, les effets secondaires de x++ et ++x seront appliqués immédiatement après l'évaluation de l'expression, tandis que C et C++ exigent seulement que l'effet secondaire soit appliqué avant le prochain point de séquence .

de C#règles sur l'évaluation de garantir que les expressions comme x = x++ , a = b++ * b++ , et a[i] = i++ sont bien définies, tandis que le C et le C++ la définition de la langue explicitement dire de telles expressions donnent lieu à un comportement Non défini (tout résultat est possible).

4
répondu John Bode 2011-10-18 21:31:36

x + x++ et x++ + x sont un exemple d'effets secondaires pathologiques dont vous ne voulez pas dépendre. x++ et ++x incrémenter x, mais en ajoutant x l'ordre d'évaluation n'est pas défini - le compilateur peut choisir de quel "côté" il évalue d'abord.

3
répondu n8wrl 2011-10-18 18:56:37

prendre en considération:

y = x + x++;

que son comportement soit défini ou non (il n'est pas défini en C et c++; apparemment il est bien défini en C#), peu importe ce que vous essayez de faire, il y a forcément une meilleure façon de l'exprimer.

si vous supposez une évaluation stricte de gauche à droite, alors ce qui précède pourrait être écrit comme:

y = x * 2;
x ++;

le sens est clair et sans équivoque pour tout lecteur qui sait quoi = , * , et ++ signifie, Et les futurs responsables de votre code ne seront pas tentés de vous traquer.

ou vous pouvez écrire x + x ou x << 1 si vous ne faites pas confiance au compilateur pour générer du code efficace, mais une telle méfiance est généralement mal placée.

Si vous insistez, vous pouvez même écrire:

y = x++ * 2;

c'est un peu court pour mes goûts personnels, mais c'est encore sans ambiguïté.

si vous voulez comprendre le code de quelqu'un d'autre (ce qui est quelque chose que les programmeurs passent beaucoup de temps à faire), alors comprendre les expressions alambiquées peut être important. Mais lorsque vous écrivez votre propre code, la clarté est plus importante que la sauvegarde des frappes (ou montrer à quel point vous connaissez bien les diagrammes de priorité de l'opérateur).

0
répondu Keith Thompson 2011-10-19 04:04:09