2010-11-08 2 views
3

J'ai (essentiellement) viennent à travers ce qui suit dans la naturecomportement non défini ou faux positif

x = x = 5; 

qui compile apparemment proprement sous la version antérieure de gcc (génère un avertissement sous gcc 4.5.1). Autant que je sache, l'avertissement est généré par -Wsequence-point. Ma question est-elle contraire au libellé de la norme concernant la manipulation de variables entre des points de séquence (c'est-à-dire un comportement indéfini par spécification) ou est-ce un faux positif de gcc (c'est-à-dire un comportement défini par spécification)? Le libellé des points de séquence est un peu difficile à suivre.

je l'ai dit essentiellement parce que ce fait, je suis tombé (dans une plus grande expression) était

x[0][0] = x[0][0] = 5; 

mais je ne pensais pas que matériel était à l'avertissement (s'il vous plaît me corriger si cela est au point et pas ce que j'ai supposé est le point crucial de la question).

+3

Que ce soit en violation du libellé de la norme ou non, c'est un code abyssal. Tuez-le avec le feu! Laissez une telle expression ne jamais obscurcir votre code à nouveau. – abelenky

+0

@abelenk est d'accord. Ce n'est pas mon code et je voulais être sûr que c'était UB avant de le mettre au CCB. – bpw1621

Répondre

5

En supposant que x est de type intégré, il attribue x deux fois sans point de séquence intermédiaire, ce qui est tout ce que vous devez savoir. Le fait que les deux affectations aient la même valeur (5), et pourrait théoriquement être optimisé en une seule affectation (si x n'est pas volatile), n'est ni ici ni là.

Au moins, c'est ainsi que j'interprète "modified" dans la valeur standard, qu'il s'agisse de la même chose que l'ancienne valeur. De même, rejeter const et affecter à un objet const est, je pense, UB indépendamment du fait que la valeur que vous affectez soit égale à la valeur précédente. Sinon, il y aura un énorme surcoût sur toutes les écritures de mémoire si une implémentation voulait mettre des littéraux de chaîne dans la ROM, pour éviter une erreur de page dans ce cas, et nous savons par l'inspection que les compilateurs n'émettent pas ce code.

Un exemple encore plus intéressant serait x[0][0] = x[0][i] = 5;, qui attribue au même objet sans point d'séquence intermédiaire si (et seulement si) i == 0, le comportement est défini de manière conditionnelle à la valeur de i.

Je ne vois pas pourquoi un compilateur peut faire quelque chose d'inattendu dans les deux cas, mais encore une fois mon manque d'imagination est sans objet :-)

Qu'est-ce que ablenky dit est exact. Si vous êtes dans un contexte où vous ne pouvez pas utiliser deux instructions, écrivez plutôt x[0][0] = 5, x[0][i] = 5 à la place. Dans les deux cas, abandonnez l'affectation redondante.

+0

Pas strictement correct: si x est un type défini par l'utilisateur avec un opérateur =, alors x = x = 5 a des points de séquence associés à chaque invocation de fonction membre et produit donc un comportement défini. –

+0

@Tony: assez bien. C'est exactement pourquoi j'ai dit "en supposant que x n'est pas un type de classe", mais j'ai oublié la possibilité qu'il a un type d'union. –

+0

était une bonne réponse pour les types de build-in, pensant simplement à discuter également des classes, car cela peut être pertinent à la question de savoir si l'affiche peut signaler cela à son "CCB". –