Namespaces
Variants

Order of evaluation

From cppreference.net

L'ordre d'évaluation des opérandes de tout opérateur C++, y compris l'ordre d'évaluation des arguments de fonction dans une expression d'appel de fonction, et l'ordre d'évaluation des sous-expressions dans toute expression est non spécifié (sauf indication contraire ci-dessous). Le compilateur les évaluera dans n'importe quel ordre, et pourra choisir un autre ordre lorsque la même expression est évaluée à nouveau.

Il n'existe pas de concept d'évaluation de gauche à droite ou de droite à gauche en C, ce qu'il ne faut pas confondre avec l'associativité gauche-droite et droite-gauche des opérateurs : l'expression f1 ( ) + f2 ( ) + f3 ( ) est analysée comme ( f1 ( ) + f2 ( ) ) + f3 ( ) en raison de l'associativité gauche-droite de operator + , mais l'appel de fonction à f3 ( ) peut être évalué en premier, en dernier, ou entre f1 ( ) ou f2 ( ) au moment de l'exécution.

Table des matières

Définitions

Évaluations

Il existe deux types d'évaluations effectuées par le compilateur pour chaque expression ou sous-expression (toutes deux facultatives) :

  • calcul de la valeur  : calcul de la valeur retournée par l'expression. Cela peut impliquer la détermination de l'identité de l'objet ( évaluation lvalue ) ou la lecture de la valeur précédemment assignée à un objet (évaluation rvalue).
  • effet secondaire  : accès (lecture ou écriture) à un objet désigné par une volatile lvalue, modification (écriture) d'un objet , synchronisation atomique (depuis C11) , modification d'un fichier, modification de l'environnement à virgule flottante (si supporté), ou appel d'une fonction effectuant l'une de ces opérations.

Si aucune effet secondaire n'est produite par une expression et que le compilateur peut déterminer que la valeur n'est pas utilisée, l'expression peut ne pas être évaluée .

Ordonnancement

Sequenced-before est une relation asymétrique, transitive et par paires entre les évaluations au sein du même thread (elle peut s'étendre à travers les threads si des types atomiques et des barrières mémoire sont impliqués).

  • Si un point de séquence est présent entre les sous-expressions E1 et E2 , alors l'évaluation de la valeur et les effets de bord de E1 sont séquencés avant toute évaluation de valeur et effet de bord de E2 .
  • Si l'évaluation A est séquencée avant l'évaluation B, alors l'évaluation de A sera terminée avant que l'évaluation de B ne commence.
  • Si A n'est pas séquencée avant B et que B est séquencée avant A, alors l'évaluation de B sera terminée avant que l'évaluation de A ne commence.
  • Si A n'est pas séquencée avant B et que B n'est pas séquencée avant A, alors deux possibilités existent :
    • les évaluations de A et B sont non-séquencées : elles peuvent être effectuées dans n'importe quel ordre et peuvent se chevaucher (au sein d'un seul thread d'exécution, le compilateur peut entrelacer les instructions CPU qui composent A et B)
    • les évaluations de A et B sont séquencées de manière indéterminée : elles peuvent être effectuées dans n'importe quel ordre mais ne peuvent pas se chevaucher : soit A sera terminée avant B, soit B sera terminée avant A. L'ordre peut être opposé la prochaine fois que la même expression est évaluée.
(depuis C11)

Règles

1) Il y a un point de séquence après l'évaluation de tous les arguments de la fonction et du désignateur de fonction, et avant l'appel effectif de la fonction.
2) Il y a un point de séquence après l'évaluation du premier opérande (gauche) et avant l'évaluation du second opérande (droit) des opérateurs binaires suivants : && (ET logique), || (OU logique), et , (virgule).
3) Il y a un point de séquence après l'évaluation du premier opérande (gauche) et avant l'évaluation du deuxième ou troisième opérande (selon celui qui est évalué) de l'opérateur conditionnel ?:
4) Il y a un point de séquence après l'évaluation d'une expression complète (une expression qui n'est pas une sous-expression : typiquement quelque chose qui se termine par un point-virgule ou une instruction de contrôle de if / switch / while / do ) et avant l'expression complète suivante.
5) Il y a un point de séquence à la fin d'un déclarateur complet.
6) Il y a un point de séquence immédiatement avant le retour d'une fonction de bibliothèque.
7) Il y a un point de séquence après l'action associée à chaque spécificateur de conversion dans les E/S formatées (en particulier, il est valide que scanf écrive différents champs dans la même variable et que printf lise et modifie ou modifie la même variable plusieurs fois en utilisant % n )
8) Il y a des points de séquence avant et immédiatement après chaque appel à une fonction de comparaison effectué par les fonctions de bibliothèque qsort et bsearch , ainsi qu'entre tout appel à la fonction de comparaison et le déplacement des objets associés effectué par qsort
(depuis C99)
9) Les calculs de valeur (mais pas les effets de bord) des opérandes de tout opérateur sont séquencés avant le calcul de valeur du résultat de l'opérateur (mais pas ses effets de bord).
10) L'effet de bord (modification de l'argument gauche) de l'opérateur d'affectation directe et de tous les opérateurs d'affectation composée est séquencé après le calcul de valeur (mais pas les effets de bord) des arguments gauche et droit.
11) Le calcul de valeur des opérateurs de post-incrémentation et post-décrémentation est séquencé avant leur effet de bord.
12) Un appel de fonction qui n'est pas séquencé avant ou séquencé après un autre appel de fonction est séquencé de manière indéterminée (les instructions CPU qui constituent différents appels de fonction ne peuvent pas être entrelacées, même si les fonctions sont intégrées)
13) Dans les expressions de liste d'initialisation , toutes les évaluations sont séquencées de manière indéterminée
14) Par rapport à un appel de fonction séquencé de manière indéterminée, l'opération des opérateurs d'affectation composée, et les formes préfixe et postfixe des opérateurs d'incrémentation et de décrémentation sont des évaluations uniques.
(depuis C11)

Comportement indéfini

1) Si un effet de bord sur un objet scalaire n'est pas séquencé par rapport à un autre effet de bord sur le même objet scalaire, le comportement est indéfini .
i = ++i + i++; // undefined behavior
i = i++ + 1; // undefined behavior
f(++i, ++i); // undefined behavior
f(i = -1, i = -1); // undefined behavior
2) Si un effet secondaire sur un objet scalaire n'est pas séquencé par rapport à un calcul de valeur utilisant la valeur du même objet scalaire, le comportement est indéfini.
f(i, i++); // undefined behavior
a[i] = i++; // undefined behavior
3) Les règles ci-dessus s'appliquent tant qu'au moins un ordonnancement admissible des sous-expressions permet un tel effet secondaire non séquencé.

Voir aussi

Priorité des opérateurs qui définit la manière dont les expressions sont construites à partir de leur représentation en code source.

Documentation C++ pour Ordre d'évaluation