Dupliqué possible: strong>
Calcules de valeur certifoncioles (points de séquence A.K.A)
Points de comportement et de séquence non définis
PRÉCÉDANCE DE L'ORDANCEMENT VS ORDRE D'ÉVALUATION P>J'essaie toujours d'envelopper ma tête autour de la manière dont l'expression suivante entraîne un comportement indéfini: p>
xxx pré> à la recherche de cela, j'ai trouvé la question suivante: < / p>
Différence entre les points de séquence et la précédente de l'opérateur? 0_o p>
J'ai lu à travers toutes les réponses mais j'ai toujours des difficultés avec les détails. L'une des réponses décrit le comportement de mon exemple de code ci-dessus comme ambigu, en termes de motivation
A code> est modifié. Par exemple, cela pourrait se passer de l'un de ces éléments suivants: p>
xxx pré> Qu'est-ce qui fait exactement
une modification code> ambiguë? Cela a-t-il à voir avec les instructions de la CPU sur différentes plates-formes et comment l'optimiseur peut tirer parti du comportement non défini? En d'autres termes, il semble indéfini à cause de l'assembleur généré? P>
Je ne vois pas une raison pour que le compilateur utilise
a = (A + 1); a ++; code>, Il semble que ça a l'air original et n'a pas beaucoup de sens. Que posséderait le compilateur pour le faire se comporter de cette façon? P>
EDIT: P>
Juste pour être clair, je comprends ce qui se passe, je ne comprends tout simplement pas comment cela peut être indéfini lorsqu'il existe des règles sur la préséance de l'opérateur (qui définit essentiellement l'ordre d'évaluation de l'expression). L'affectation se produit durer dans ce cas, de sorte que
a ++ code> doit d'abord être évalué pour déterminer la valeur à attribuer à
A code>. Donc, ce que j'attends, c'est que
A code> est modifié en premier, pendant l'incrément post-correction, mais donne une valeur à attribuer à
A code> (deuxième modification). Mais les règles de la priorité de l'opérateur semblent rendre le comportement très clair pour moi, je ne trouve pas d'où il y a une "salle de gueule" pour qu'il ait un comportement indéfini. P> blockQquote>
6 Réponses :
Ceci est probablement trop simpliste une explication, mais je pense que c'est parce qu'il n'ya aucun moyen de résoudre lorsque le code est "fait" avec "A". Est-ce fait après l'incrément ou la mission? La résolution finit par être circulaire. Affectation Après l'incrément modifie la sémantique du moment où la valeur incrémentée est appliquée. C'est-à-dire que le code n'est pas effectué avec "A" jusqu'à ce que "A" est incrémenté, mais un n'est pas incrémenté tant que la suite de l'affectation est faite. C'est presque une version linguistique d'une impasse. p>
Comme je l'ai dit, je suis sûr que ce n'est pas une excellente explication "académique", mais c'est comme ça que je la bouteille entre mes propres oreilles. J'espère que c'est utile. P>
Les règles de priorité précisent l'ordre dans lequel les expressions sont évaluées, mais les effets secondaires ne doivent pas se produire pendant l'évaluation. Ils peuvent être arrivés à tout moment avant le prochain point de séquence. p>
Dans ce cas, l'effet secondaire de l'incrément est séquencé ni auparavant ni après l'affectation, l'expression a donc un comportement indéfini. P>
La première réponse dans la question que vous avez liée à explique exactement ce qui se passe. Je vais essayer de le reformuler pour le rendre plus clair. P>
Le précédent de l'opérateur définit l'ordre du calcul des valeurs via des expressions. Le résultat de l'expression Cependant em> strud>, la modification de la variable Les expressions entraînent des valeurs, mais certaines expressions peuvent avoir des effets secondaires. L'expression Les points de séquence définissent lorsque des effets secondaires sont visibles pour les expressions évaluées après ces points de séquence. La précédente de l'opérateur n'a rien à voir avec des points de séquence. C'est à quoi C / C ++ définit les choses. P> (a ++) code> est bien compris. P>
A code> ne fait pas partie de l'expression em>. Oui vraiment. C'est la partie que vous rencontrez de la difficulté à comprendre, mais c'est simplement comment C et C ++ le définissent. P>
A = 1 code> a une valeur de
1 code>, mais il a également l'effet secondaire em> de réglage de la variable
A code > Pour
1 code>. En ce qui concerne la manière dont C et C ++ définir des choses, celles-ci sont deux étapes différentes em>. De même,
A ++ code> a une valeur et un effet secondaire. P>
La séparation du traitement des effets secondaires et de l'évaluation de l'expression est définitivement ce que j'ai des problèmes, car je me sens juste avoir un mauvais sentiment qu'il y a une situation là où la valeur de l'effet secondaire dépend de la Résultat de l'expression, auquel cas les effets secondaires doivent être traités avant l'évaluation complète de l'expression. Les effets secondaires sont simplement une modification d'un bloc de mémoire quelque part. Et si la même expression fonctionne sur ce bloc de mémoire? Je ne peux penser à aucun exemples hors de la main qui ferait cela, cependant.
@RobertDailey: C'est le point: si vous écrivez une expression, où la valeur calculée par cette expression est basée sur des effets secondaires qui ne sont pas correctement séquencés, vous obtenez un comportement indéfini. C'est un système de deux couches: vous avez besoin de priorité de l'opérateur, mais les valeurs de la source doivent être séquencées à tous les effets secondaires des expressions antérieures.
@Robert "Et si la même expression fonctionne sur ce bloc de mémoire". Je pense que c'est le point. C et C ++ (pour le meilleur des pires) Ne définissez pas la la commande i> dans laquelle des effets secondaires ont lieu, mais ils disent quand i> ces effets secondaires doivent être complète < / I> (par le point de séquence suivant avant C ++ 11, avant la prochaine opération "séquencée après" en C ++ 11). Par conséquent, la règle "ne modifie pas quelque chose deux fois entre deux points de séquence" pour prévenir les ambiguïtés.
Pourquoi le rendre indéfini cependant? C'est mon point. a = A ++ code>, pourquoi ne pas nécessiter que les effets secondaires soient traités à la demande, dès que l'évaluation atteint ce point? Modifier
A code> à égal 1, puis renvoyez 0, puis assignez enfin 0 à
A code>. Je ne trouve aucune raison de rendre le comportement indéfini. Que pensaient-ils quand ils l'ont mis de cette façon dans la norme?
@RobertDailey: Comment i> c'est un comportement indéfini est une question différente de pourquoi i> c'est. Ce dernier est essentiellement spéculatif et a probablement à voir avec la liberté d'action raisonnable des compilateurs et faciliter leur emploi. Ou c'est peut-être un problème historique.
@RobertDailey: Ou peut-être que les écrivains de spécification étaient suffisamment sages pour savoir que le code endossible comme a = A ++ + ++ a code> est une idée horrible;)
@Nicolbolas "horrible idée", est-ce votre opinion personnelle? Où sont les faits? :) Je ne peux pas penser à un cas d'utilisation qui le rendrait horrible, ni destructeur, ou quoi que ce soit d'autre. Mais, horrible en termes de lisibilité et du fait qu'il n'a pas beaucoup de sens de le faire, je suis d'accord.
Le point ici est que sur certaines architectures de la CPU, comme Intel Itanium, ces deux opérations pourraient être parallélisées par le compilateur au niveau de l'instruction - mais la fabrication de votre construction bien définie interdire cela. Au moment de la spécification du point de séquence, ces architectures étaient surtout hypothétiques et que Itanium était un flop, il est bien arguant qu'en 2012, une grande partie de cela est une complexité inutile dans la langue. Il n'y a essentiellement aucun désavantage possible sur aucune architecture toujours en usage commun et même pour Itanium, l'avantage de la performance était minimal et le mal de tête d'écrire un compilateur pouvant même en tirer parti était énorme. P>
Notez également que, dans C ++ 11, des points de séquence ont été remplacés par séquence avant et séquencé après, ce qui a fait plus de situations comme celle-ci bien définie. P>
Même sur des machines modernes, un problème possible est que si a code> et
b code> sont des références identifiant le même
int code> et
x code> et
y code> sont
int code> variables, code comme
a = b ++; x = a; ...; y = b; code> peut être évalué sous forme
temp = b; A = Temp; B = TEMP + 1; x = TEMP; ... Y = A; code>, se comporter comme si
a code> change spontanément entre les affectations sur
x code> et
y code>. J'aimerais voir la norme Définir un modèle d'exécution qui reconnaîtrait non-déterminisme contagieux mais resterait sur les rails, car les avantages marginaux de permettre des comportements arbitraires au-delà, mais il y aurait une utilité pour limiter ...
... Les conséquences des missions qui se chevauchent dans les cas où peu importe quelles valeurs sont calculées dans certains cas de bords à condition que le code reste sur les rails. Obliger les programmeurs à se protéger de ces affectations, même dans ces cas pourraient rendre le code moins efficace que de les laisser produire des résultats arbitraires.
Cette déclaration (parce que c'est un postinCrètent) et p> Ces affectations entraînent clairement une valeur finale différente pour Les rédacteurs de la norme C n'ont pas indiqué que les deux missions doivent être écrites à Le résultat est, il (cette déclaration particulière) ne s'écrase pas. , mais votre programme ne peut plus compter sur une valeur spécifique. p> p> a = A ++ code> a deux résultats et deux assignations:
A code>. p>
a code> d'abord et quel second, les écrivains de compilateur sont donc libres de choisir celui qu'ils aiment, dans une situation donnée. P>
Permettez-moi de courir dans le problème de base dans la déclaration Déterminez la valeur incrément Attribuez l'ancienne valeur à Il y a deux manières possibles que cela pourrait être séquencé: p>
stocke l'original Évaluez puisque il n'y a pas de séquence prescrite em>, l'une de ces opérations est autorisée. Mais ils ont un résultat ultime différent. Aucune des séquences n'est plus naturelle que l'autre. P> a = A ++ code>. Nous voulons atteindre toutes les choses suivantes: p>
A code> (la valeur de retour de
a ++ code>, n ° 1) p> li>
a code> (l'effet secondaire de
a ++ code>, n ° 2) p> li>
A code> (effet de l'affectation, n ° 3) p> li>
ul>
A code> dans
A code> (un non-op); Ensuite, incrément
a code>. Identique à
a = a; ++ A; code>. C'est la séquence n ° 1- # 3- # 2. P> li>
A code>, incrément
A code>, attribuez la valeur d'origine sur
A code>. Identique à
b = a; ++ a; a = b; code>. C'est la séquence n ° 1- # 2- # 3. P> li>
ol>
Vous demandez de modifier
A code> deux fois i> sans point de séquence: une fois dans l'affectation, et une fois comme effet secondaire du
++ code>. La norme ne spécifie pas ce que vous voulez dire.
@KerReksb: Je savais déjà que
A code> est modifié deux fois, ce que je demande, c'est ce qui n'est pas défini exactement à ce sujet. "La norme ne spécifie pas ce que tu veux dire" - Quoi? Il spécifie l'ordre des opérations et la priorité de l'opérateur, il précise très clairement ce que l'expression signifie. Je peux le regarder et savoir ce qui se passe, dans l'ordre.
Precedance de l'opérateur Merealy Désambiguats entre plusieurs manières possibles d'analyse d'une expression (réfléchir à
* p ++ code>, ce qui signifie
(* p) ++ code>), il n'aide pas à déterminer la commande dans quelles modifications d'un objet ont lieu.
Oui, les gars, il y a des doublons, mais quels sont les bons duplicats pour moi si les réponses ne me donnent aucun sens pour moi? Mon objectif est d'obtenir des réponses différentes, de mieux comprendre.
@Robert - Comment est-ce important? Vous essayez de changer la valeur de
A code> deux fois dans la même expression. Pourquoi voudriez-vous faire cela? Il n'y a absolument aucune utilisation pratique pour cela.
@Bopersson je n'ai jamais dit que j'utilise cela dans la pratique. Il s'agit d'une session éducative, à mieux comprendre la sémantique de C ++ telle que définie par la norme.
@Robert Cette réponse m'a aidé beaucoup à comprendre cela.
@Robert - mais il n'y a rien à comprendre. :-) Dans le monde réel, il n'est pas nécessaire de mettre à jour
a code> deux fois, alors pourquoi nous soucions-nous?
++ A code> fonctionnera bien,
a = A ++ + ++ a - A - code> ne sera pas. Utilisez celui qui fonctionne!
@ROBERT: "Mon objectif est d'obtenir des réponses différentes" alors vous utilisez une Bounty i>, affirmant que vous ne comprenez pas les réponses actuelles sur cette question.
Je pense que vous essayez peut-être de sur-analyser la situation. Vous avez du code que, par les règles de la langue, a comportement indéfini i>. À ce stade, vous ne pouvez appliquer aucune logique telle que "si elle n'avait pas comportement indéfini i>; cela ne pourrait avoir qu'un seul sens pour ne pas être indéfini". C'est ce qu'il est.
@Charlesbileyney une des plus grandes philosophies de la science: toujours question de choses. Il y a toujours une raison pour laquelle quelque chose n'est pas défini. Lorsque le Comité a décidé de ne pas faire de règles qui le feraient autrement bien défini, je veux savoir quels scénarios jouaient dans leur esprit.
Mais une norme de programmation n'est pas un phénomène naturel auquel vous pouvez appliquer une méthode et un raisonnement scientifique. C'est un ensemble de règles conçues par les humains.
@CharlesBiley et le gouvernement et le droit sont la même chose, mais simplement parce qu'il y a des règles en place ne les rend pas corrects. Tout comme j'essaierais de comprendre pourquoi quelque chose a une règle, je veux comprendre pourquoi quelque chose n'a pas de règle. Vous me comprenez mal, vous pensez que j'essaie de changer la norme ou que c'était différent. Non, j'essaie de comprendre pourquoi il est indéfini. S'il vous plaît soyez clair sur cela.
Ok, mais quand j'ai répondu à votre commentaire, il est simplement lu: "@charlesbiley une des plus grandes philosophies sur la science: toujours question de choses.". J'espère que ma réponse a plus de sens dans ce contexte.
La programmation @CHARLESBAILEY est toujours une science et la science ne signifie pas toujours que quelque chose doit être un phénomène naturel. Cependant, C ++ est quelque chose que vous pouvez certainement appliquer une méthode et un raisonnement scientifique, et la norme en est la preuve (c'est un résultat direct de telle). De plus, la norme n'est pas une entité fixe, elle évolue (exemple: C ++ 11) en raison de l'interrogatoire scientifique (par exemple, comment pouvons-nous faire cela mieux? ") - Désactiver le sujet maintenant, mais c'est ce que je voulais dire.
@RobertDailey: Si vous regardez ma réponse à la question à la question que j'ai proposée en double, cela donne des exemples assez spécifiques et (OMI) assez raisonnables pour la manière dont vous vous retrouveriez avec un comportement problématique à partir du type de code que vous avez discuté . Si vous avez déjà examiné cela et que vous trouvez mon raisonnement difficile à suivre (ou de loin), j'apprécierais d'en entendre parler. Je n'ai aucun problème du tout avec faire une édition si cela clarifiera la réponse.