Question

Il y a quelques jours il y avait une discussion de savoir si l'expression

  

i = i + 1 ++

UB invoque (Comportement non défini) ou non.

Enfin, la conclusion a été faite qu'il invoque UB comme la valeur de « i » change plus d'une fois entre deux points de séquence.

Je participais à une discussion avec Johannes Schaub dans ce même fil. Selon lui

  

i = (i, i ++, i) 1 ------ (1) / * invoque UB et * /

I dit (1) ne pas invoquer UB parce que les effets secondaires des sous-expressions précédentes sont effacées par l'opérateur virgule « » entre i et i ++ et entre i ++ et i.

Il a ensuite donné l'explication suivante:

  

"Oui le point de séquence après i ++ complète tous les effets secondaires avant, mais il n'y a rien qui empêche l'effet secondaire d'affectation se chevauchent avec l'effet secondaire de i ++. Le problème sous-jacent est que l'effet secondaire d'une cession est non spécifié se produire avant ou après l'évaluation des deux opérandes de la mission, et donc des points de séquence ne peut rien faire en ce qui concerne la protection de celle-ci: séquence indique induire un ordre partiel: Juste parce qu'il ya un point de séquence avant et après i ++ ne signifient tous les effets secondaires sont séquencés par rapport à i .

     

En outre, notez que seulement un point de séquence ne veut rien dire: L'ordre des évaluations est pas dictée par la forme de code. Il est dicté par des règles sémantiques. Dans ce cas, il n'y a pas de règle sémantique dire lorsque l'effet secondaire d'affectation se produit en ce qui concerne l'évaluation de ses deux opérandes ou subexpressions ces opérandes ».

La déclaration écrite en « gras » me confondre. Pour autant que je sais:

« A certains points spécifiés dans les points de séquence appelée séquence d'exécution, tous les effets secondaires des évaluations antérieures est complète et sans effets secondaires des évaluations subséquentes sont ont eu lieu. »

Depuis, les opérateurs de virgule précisent également l'ordre d'exécution l'effet secondaire de i ++ ont été annulés lorsque nous atteignons le dernier i.He (Johannes) aurait eu raison avait l'ordre d'évaluation été non spécifiée (mais en cas de opérateur virgule, il est bien précisé).

Je veux juste savoir si (1) invoque UB ou non ?. Quelqu'un peut-il donner une autre explication valable?

Merci!

Était-ce utile?

La solution

La norme C dit ceci au sujet des opérateurs d'affectation (C90 ou C99 6.3.16 6.5.16 Opérateurs d'affectation):

  

L'effet secondaire de mise à jour de la valeur mémorisée de l'opérande gauche doit se produire entre le précédent et le point suivant de la séquence.

Il me semble que, dans la déclaration:

i=(i,i++,i)+1;

le point de séquence « précédent » à l'opérateur d'affectation serait le deuxième opérateur virgule et le point de séquence « suivant » serait la fin de l'expression. Je dirais donc que l'expression n'invoque pas un comportement non défini.

Cependant, cette expression:

*(some_ptr + i) = (i,i++,i)+1;

aurait un comportement non défini parce que l'ordre d'évaluation des 2 opérandes de l'opérateur d'affectation est indéfini, et dans ce cas, au lieu du problème étant quand l'effet secondaire de l'opérateur d'affectation a lieu, le problème est que vous ne savez pas si la valeur de i utilisé dans l'opérande de poignée gauche sera évaluée avant ou après le côté droit. Cet ordre de problème d'évaluation ne se produit pas dans le premier exemple parce que dans cette expression la valeur de i est pas utilisé dans le côté gauche - tout ce que l'opérateur d'affectation est intéressé est le « lvalue-ness » de i .

Mais je pense aussi que tout cela est assez peu précis (et ma compréhension des nuances en jeu sont assez peu précis) que je ne serais pas surpris si quelqu'un peut me convaincre du contraire (soit sur le nombre).

Autres conseils

Je crois que l'expression suivante comportement a certainement non défini.

i + ((i, i++, i) + 1)

La raison est que l'opérateur virgule spécifie les points de séquence entre les sous-expressions entre parenthèses, mais ne précise pas où dans cette séquence l'évaluation de l'opérande gauche de + se produit. Une possibilité est entre les points de séquence entourant i++ et cela porte atteinte à la 5/4 comme i est écrit entre deux points de séquence, mais est aussi lu deux fois entre les mêmes points de séquence et non seulement pour déterminer la valeur à stocker, mais aussi pour déterminer la la valeur du premier opérande de l'opérateur de +.

Ce comportement a aussi indéfini.

i += (i, i++, i) + 1;

Maintenant, je ne suis pas sûr de cette déclaration.

i = (i, i++, i) + 1;

Bien que les mêmes principes sont applicables, i doivent être « évaluées » en tant que lvalue modifiable et peut être fait à tout moment, mais je ne suis pas convaincu que son valeur est toujours lire dans le cadre de cette. (Ou est-il une autre restriction que l'expression est contraire à provoquer UB?)

Le (i, i++, i) sous-expression se produit dans le cadre de la détermination de la valeur à stocker et en ce que la sous-expression contient un point de séquence après le stockage d'une valeur de i. Je ne vois aucune façon que cela ne nécessite l'effet secondaire de i++ être terminée avant la détermination de la valeur à stocker et donc le plus tôt possible que l'effet secondaire d'affectation pourrait se produire.

Après ce point sequnce la valeur de i est lu au plus une fois et seulement pour déterminer la valeur qui sera stockée retour à i, cette dernière partie est très bien.

i=(i,i++,i)+1 ------ (1) /* invokes UB as well */

Il n'invoque pas un comportement non défini. L'effet secondaire de i++ aura lieu avant l'évaluation du point suivant de la séquence, qui est désignée par la suite par des virgules, et aussi avant l'affectation.

Nice langue sudoku, cependant. : -)

modifier. Il y a une explication plus élaborée

Je suis confus au début sur la déclaration Johannes' (de litb), mais il a mentionné que:

i = (i, ++i, i) +1
  


  Si est l'affectation, et est un incrément. :s: est un point de la séquence, alors les effets secondaires peuvent être séquencées comme suit entre les points de séquence: (i :s: i++< a ><n> :s: i) + 1. La valeur du i scalaire a été changé deux fois entre le premier et le deuxième point de séquence ici. L'ordre dans lequel l'affectation et l'incrément se produit est non spécifié, et depuis entre eux il n'y a pas de point de séquence, il est même pas atomique par rapport à chaque other.This est une commande autorisée permises par l'ordre quelconque de ces effets secondaires.

     

Ceci est différent de (i++, i++), parce que l'ordre d'évaluation des deux sous-expressions est de gauche à droite, et au point de séquence entre eux, l'augmentation de l'évaluation précédente est terminée, et l'incrément suivant ne doit pas avoir encore pris endroit. Ceci impose qu'il n'y a pas de changement de la valeur de i entre deux points de séquence, ce qui rend (i++, i++) valide
  

Cela me fait penser à la séquence mentionnée par litb est invalide parce que par C99:

  

6.5.16.1 (2) Dans une simple affectation (=), la valeur de l'opérande droit est converti au type de l'expression d'affectation et remplace la valeur stockée dans l'objet désigné par l'opérande gauche.

i.e.. la valeur de l'opérande droit doit être connue avant que l'effet secondaire d'affectation (modification de la valeur stockée dans l'objet correspondant à l'opérande gauche)

  

05/06/17 (2) L'opérande gauche d'un opérateur virgule est évalué comme une expression de vide; il existe un point de séquence après son évaluation. Ensuite, l'opérande de droite est évaluée; le résultat a son type et la valeur.

i.e.. l'opérande de l'opération la plus à droite de la virgule doit être évaluée pour connaître la valeur et le type de l'expression par des virgules (et la valeur du droit opérande pour mon exemple).

Donc dans ce cas, le « point de séquence précédente » pour l'effet secondaire d'affectation serait, en effet, être le plus à droite opération de virgule. La séquence possible communiquée par Johannes est invalide.

S'il vous plaît me corriger si je me trompe.


scroll top