Aujourd'hui, je suis venu une croix un article de Eric Lippert où il essayait de nettoyer le mythe entre la priorité des opérateurs et l'ordre d'évaluation. À la fin, il y avait deux extraits de code qui m'a confondu, voici le premier extrait: Maintenant, lorsque je pense à la valeur de la valeur variable, je le calculez simplement à être une. Voici comment je pensais que cela fonctionne. apparemment c'est faux. J'ai essayé de rechercher les spécifications C # pour une déclaration explicite sur lorsque l'incrément se produit réellement, mais n'a pas trouvé. de
p>
Le deuxième extrait est d'un commentaire de Eric's Href = "http://blogs.msdn.com/ericlippert/archive/2009/08/10/PRECEDENCE-VS-ORD-REDux.aspx" rel = "NOFOOL NOREFERRER" > Blog POST sur le sujet: P> int[] data = { 11, 22, 33 };
int i = 1;
data[i++] = data[i] + 5;
6 Réponses :
L'opération postincrimentation se produit dans le cadre d'évaluer l'expression globale. C'est un effet secondaire qui se produit après l'évaluation de la valeur mais avant que toutes les autres expressions soient évaluées.
En d'autres termes, pour toute expression E, E ++ (si légale) représente quelque chose comme (pseudo-code): P> < Pré> xxx pré>
c'est toutes les parties em> de l'évaluation E ++, avant toute autre chose n'est évaluée. P> Voir la section 7.5.9 de la spécification C # 3.0 pour plus de détails . P> En outre, pour les opérations d'affectation dans lesquelles la LHS est classée comme variable (comme dans ce cas), le LHS est évalué avant em> le RHS est évalué. p> donc dans votre exemple: p> est équivalent à: p> le bit correspondant de la spécification Pour cela, la section 7.16.1 (spécifique C # 3.0). P> p>
Cela, et les expressions (y compris les missions) sont évaluées à droite sauf lorsque la priorité de l'opérateur dicte autrement. Donc, les données [i ++] (le côté gauche de l'affectation) est évalué avant les données [i] sur le côté droit.
@Lbushkin: Je pense que je montais exactement ce but pendant que vous commenciez :)
@Lbushkin faux. Microsoft dit explicitement que la mission (=) et le ternaire (? :) Les opérateurs sont résolus de droit à gauche.
"L'opération postincrimentation se produit immédiatement après l'évaluation de l'expression postincrissante est évaluée" J'aimerais le mettre de cette façon: l'expression postincration a une valeur comme toutes les expressions. Il a également un effet secondaire (contrairement à la plupart des expressions triviales). Vous pouvez y penser comme quelque chose comme un appel de méthode. La valeur qu'une méthode renvoie est totalement indépendante des effets secondaires qu'il pourrait avoir. Fondamentalement, au moment de l'évaluation, une opération postincrimentation effectue un effet secondaire tout en retournant la valeur initiale de l'opérande comme valeur.
@Novash: Comment les opérateurs ternaires pourraient-ils être résolus de droit à gauche? L'expression la plus gauche doit être résolue avant de décider que les deux autres expressions seront résolues (l'autre expression n'est même pas exécutée).
La section 7.16.1 traite des types booléens. Vous n'avez pas voulu dire 7.13.1, qui traite de la mission? De plus, la section 7.5.9 qui traite de Post ++ Spécifie que la valeur n'est modifiée qu'après que l'appel fixé se produit.
@JPBOCHI Il est considéré comme associatif juste quand il est empilé.
@Leahn: Je pense que vous devez regarder une version différente de la spécification pour moi. Je regarde la spécification C # 3.0, où 7.16.1 est très affectant ... et le LHS de l'affectation est évalué en premier.
@Mehrdad: Je vais éditerai un peu, mais pas tout à fait dans cette mesure. @Leahn: la version de la spécification C # que vous avez liée est définitivement ancienne - elle ne couvre pas les expressions de la requête, par exemple.
@Jon Skeet: Je blâme Microsoft. :) Cependant, comme je l'ai dit dans un autre poste, je suis corrigé. J'ai mal compris ce que j'ai lu. Les commandes de résolution correcte sont les suivantes: i = 1, trouvez l'adresse des données [1], ajoutez 1 à i, trouvez l'adresse des données [2], ajoutez 5 à la valeur des données [2], attribuez le résultat des données [1]
@Jon Skeet, donc pour le premier extrait, il va déréférenference Arr [0] puis stocker sa valeur quelque part, puis incrémenter arr [0]. Il utiliserait ensuite la valeur de la température stockée pour évaluer l'expression (l'arrondi externe [0]) qui récupérera la valeur incrémentée. À droite, ou je manque quelque chose d'autre?
@ 7ALWAGY: Oui, c'est vrai (en supposant que je vous ai suivi correctement!)
@Jon: Il ne fait aucun doute que vous avez raison. Mais pourquoi dans le monde, quelqu'un devrait écrire du code comme celui-ci? Où est l'idée de la lisibilité ou devrais-je dire la compréhensibilité?
@shahkalpeh: Évidemment, ces exemples eux-mêmes sont hideusement illisibles - mais je soupçonne qu'il existe d'autres cas qui semblent beaucoup plus lisibles, mais nécessitent les mêmes détails pour être entièrement i> compris. Ces exemples sont bons pour démontrer l'ordre d'évaluation.
data[i++] // => data[1], then i is incremented to 2 data[1] = data[2] + 5 // => 33 + 5
Je ne suis pas d'accord avec vous. La mise en œuvre indique que l'opérateur d'affectation est la priorité la plus basse et résolue de droite à gauche. Le gars est correct sur ses hypothèses, selon les spécifications de la langue. msdn.microsoft.com/en-us/library/aa691323 (Vs.71) .aspx
@Leahn Novash: Vous êtes à nouveau confuses associativité avec l'ordre d'évaluation. "A = B = C" est juste associatif "A = (B = C)", mais qui ne dit rien sur l'ordre d'évaluation. L'ordre d'évaluation en C # est toujours laissé à droite.
J'ai encore lu les spécifications plus attentivement. Je me suis trompé.
La cause peut être que certains compilateurs optimisent I ++ pour être ++ i. La plupart du temps, le résultat final est le même, mais il me semble être l'une de ces rares occasions lorsque le compilateur est faux. P>
Je n'ai aucun accès à Visual Studio pour le confirmer, mais essayez de désactiver l'optimisation du code et de voir si les résultats resteront les mêmes. P>
I ++ et ++ I sont différents et sont utilisés de différentes manières. Tout compilateur qui convertit I ++ vers ++, j'inviterais la colère de nombreux développeurs.
Heureusement, c # définit son comportement plutôt mieux que cela.
Je conviens que les optimisations de compilateur, de gitter ou de processeur peuvent avoir lieu, mais cela se produira si seuls les résultats des optimisations sont indiscernables du résultat souhaité sur une application à une seule application: blogs.msdn.com/ericlippert/archive/2009/08/10/... a >
Je m'attendrais à ce que l'opérateur post-incrément augmente la variable après l'utilisation de sa valeur. Dans ce cas, la variable est incrémentée avant la deuxième référence à la variable.
Si ce ne serait pas, vous pouvez écrire P>
data[i++] = data[i++] + data[i++] + data[i++] + 5
Pour le premier extrait, la séquence est la suivante: p>
Valeur Code>. Li>
- valeur = 1 li>
ol>
Pour le deuxième extrait, l'évaluation est toujours de gauche à droite. P>
- Où stockons-nous le résultat? Dans les données [i ++], qui sont des données [1], mais maintenant i = 2 li>
- Que ajoute-t-on? données [i] + 5, qui est maintenant des données [2] + 5, qui est 38. li>
ol>
La pièce manquante est que "post" ne signifie pas "après tout le reste". Cela signifie simplement "immédiatement après que je récupère la valeur actuelle de cette variable". Un événement post-incrément qui se produit "au milieu de" une ligne de code est complètement normal. P>
Vous devez penser aux assignations en trois étapes:
si vous avez quelque chose comme p> alors a () fonctionnera en premier, alors c () s'exécutera, puis le setter de la propriété B sera exécuté. . P> essentiellement, vous devez penser à votre relevé comme p>
Votre cinquième étape n'est pas correcte de toute façon. "Ajouter à la valeur de l'étape 2 1 --NOWR arr [0] = 1." La valeur prise / copiée de la matrice est incrémentée avec une, mais la valeur dans b> la matrice n'est pas touchée. Donc l'instruction arr [0] = 1 est false. La valeur copiée de l'arr [0] = 1 à l'étape 5.
Eh bien, je viens de courir le code et j'ai eu la valeur 0 pour la 1ère réponse et {11,27,33} Comme le second ... est-ce que ce compilateur est spécifique?
@Swabha vous êtes sûr que vous utilisez c #?