27 votes

Quelle est la différence entre un point de séquence et la priorité d'un opérateur?

Considérons le schéma classique: exemple de point:

i = i++;

Le C et le C++ normes de l'état que le comportement de l'expression ci-dessus est undefined, car l'opérateur = n'est pas associée à un point de séquence.

Ce qui me confond, c'est que ++ a une priorité plus forte que l' = et donc, l'expression ci-dessus, basé sur la préséance, doit évaluer i++ en premier et ensuite faire la mission. Donc, si nous commençons avec i = 0, nous devrions toujours à la fin avec l' i = 0 (ou i = 1, si l'expression a été i = ++i) et pas un comportement indéfini. Ce qui me manque?

31voto

dasblinkenlight Points 264350

Tous les opérateurs de produire un résultat. En outre, certains opérateurs, tels que l'opérateur d'assignation = et composé des opérateurs d'affectation (+=, ++, >>=, etc.) produire des effets secondaires. La distinction entre les résultats et les effets secondaires est au cœur de cette question.

La priorité de l'opérateur régit l'ordre dans lequel les opérateurs sont appliqués à produire leurs résultats. Par exemple, les règles de priorité exiger que * avant +, + avant &, et ainsi de suite.

Cependant, la priorité de l'opérateur ne dit rien au sujet de l'application d'effets secondaires. C'est là que la séquence de points (séquencée avant, après avoir séquencé, etc.) entrent en jeu. Ils disent que, pour une expression être bien défini, l'application d'effets secondaires pour le même emplacement dans la mémoire doivent être séparés par un point de séquence.

Cette règle est brisé par l' i = i++, parce que les deux ++ et = appliquer leurs effets secondaires sur la même variable i. Tout d'abord, ++ va, car il a une priorité plus élevée. Il calcule sa valeur en prenant is'valeur d'origine avant l'incrément. Ensuite, = va, car il a une plus faible priorité. Son résultat est aussi à l'origine de la valeur de i.

La chose essentielle qui manque ici est une séquence de points de séparer les effets secondaires des deux opérateurs. C'est ce qui rend le comportement indéfini.

14voto

Lundin Points 21616

La priorité de l'opérateur (et l'associativité) de l'état l'ordre dans lequel l'expression est interprétée et exécutée. Toutefois, cela ne dit rien sur l' ordre d'évaluation des opérandes, qui est un terme différent. Exemple:

a() + b() * c()

La priorité de l'opérateur dicte que le résultat de l' b() et le résultat d' c() doit être multipliée avant l'ajout de concert avec le résultat de l' a().

Cependant, il ne dit rien sur l'ordre dans lequel ces fonctions doivent être exécutées. L'ordre d'évaluation de chaque opérateur indique ce. Le plus souvent, l'ordre d'évaluation n'est pas spécifié (comportement non spécifié), ce qui signifie que la norme permet au compilateur de le faire dans n'importe quel ordre il aime. Le compilateur n'a pas besoin de document de la présente ordonnance ni ne doivent se comporter de manière cohérente. La raison pour cela est de donner des compilateurs plus de liberté dans l'expression de l'analyse, sens de l'accélération de la compilation et éventuellement aussi d'accélérer l'exécution du code.

Dans l'exemple ci-dessus, j'ai écrit un programme de test simple et mon compilateur exécuté les fonctions ci-dessus dans l'ordre a(), b(), c(). Le fait que le programme doit s'exécuter à la fois b() et c() avant de pouvoir multiplier les résultats, ne veut pas dire qu'il faut évaluer ces opérandes dans une commande donnée.

C'est là que la séquence de points. C'est un point donné dans le programme où toutes les évaluations précédentes (et activités) doit être effectué. Si la séquence de points sont pour la plupart liés à la commande de l'évaluation et non pas la priorité de l'opérateur.

Dans l'exemple ci-dessus, les trois opérandes sont séquencé par rapport à l'autre, ce qui signifie qu'aucun point de séquence dicte l'ordre d'évaluation.

Par conséquent, il s'avère problématique lorsque les effets secondaires sont introduit dans séquencé expressions. Si nous écrivons i++ + i++ * i++, alors que nous ne savons pas encore à l'ordre dans lequel ces opérandes sont évalués, de sorte que nous ne pouvons pas déterminer ce que sera le résultat. C'est parce que les deux + et * ont non spécifié/non séquencés afin de l'évaluation.

Avions-nous écrit, i++ || i++ && i++, alors le comportement serait bien défini, parce que l' && et || spécifie l'ordre d'évaluation à gauche-à-droite et il y a un point de séquence entre l'évaluation de la gauche et de l'opérande de droite. Ainsi, if(i++ || i++ && i++) est parfaitement portable et coffre-fort (même si illisible) du code.


Quant à l'expression i = i++;, le problème ici est que l' = est définie comme (6.5.16):

Les effets secondaires de la mise à jour de la valeur de l'opérande de gauche est séquencé après la valeur des calculs de la gauche et la droite opérandes. Les évaluations de la opérandes sont séquencé.

Cette expression est en fait proche d'être bien défini, car le texte dit que l'opérande de gauche ne doit pas être mis à jour avant de l'opérande de droite est calculée. Le problème, c'est la dernière phrase: l'ordre d'évaluation des opérandes est non spécifié/non.

Et puisque l'expression contient l'effet secondaire de l' i++, il invoque un comportement indéfini, puisque nous ne pouvons pas savoir si l'opérande i ou l'opérande i++ est évalué en premier.

(Il n'y a plus que ça, étant donné que la norme indique également qu'un opérande ne doit pas être utilisé deux fois dans une expression à des fins différentes fins, mais c'est une autre histoire.)

0voto

haccks Points 33022

La priorité de l'opérateur et de l'ordre de l'évaluation sont deux choses différentes. Jetons un coup d'oeil sur eux un par un:

La priorité de l'opérateur règle: Dans une expression opérandes lié plus serré pour les opérateurs ayant une priorité plus élevée.

Par exemple

int a = 5;
int b = 10;
int c = 2;
int d;

d = a + b * c;  

Dans l'expression a + b * c, la préséance de l' * est plus élevé que celui de l' + et, par conséquent, b et c va se lier d' * et d'expression sera analysée comme a + (b * c).

Afin de règle d'évaluation: Il décrit la façon dont les opérandes seront évaluées dans une expression. Dans la déclaration

 d = a>5 ? a : ++a; 

a est garanti pour être évalués avant d'évaluation de l' ++b ou c.
Mais pour l'expression a + (b * c), bien qu' * a une priorité plus élevée que celle de l' +, il n'est pas garanti qu' a seront évaluées, que ce soit avant ou après l' b ou c et même pas b et c commandés pour leur évaluation. Même a, b et c pouvez évaluer dans n'importe quel ordre.

La règle est simple que: la priorité de l'opérateur est indépendante de l'ordre d'évaluation et vice versa.

Dans l'expression i = i++, la priorité de l' ++ indique au compilateur de lier i avec ++ de l'opérateur et c'est tout. Il ne dit rien sur l'ordre d'évaluation des opérandes ou qui les effets secondaires (l'un par = exploitant ou de l'un par l' ++) devrait avoir lieu en premier. Compilateur est libre de faire n'importe quoi.

Nous allons renommer l' i à gauche de l'affectation être il et au droit de cession (dans l'expression i++) être ir, alors l'expression être comme

il = ir++     // Note that suffix l and r are used for the sake of clarity.
              // Both il and ir represents the same object.  

Maintenant compilateur est libre d'évaluer l'expression il = ir++ , soit comme

temp = ir;      // i = 0
ir = ir + 1;    // i = 1   side effect by ++ before assignment
il = temp;      // i = 0   result is 0  

ou

temp = ir;      // i = 0
il = temp;      // i = 0   side effect by assignment before ++
ir = ir + 1;    // i = 1   result is 1  

a abouti à deux résultats différents, 0 et 1 qui dépend de la séquence des effets secondaires par l'affectation et de l' ++ et donc invoque UB.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X