C Language
Points de séquence
Recherche…
Remarques
Norme internationale ISO / IEC 9899: 201x Langages de programmation - C
L'accès à un objet volatile, la modification d'un objet, la modification d'un fichier ou l'appel d'une fonction effectuant l'une de ces opérations sont tous des effets secondaires , à savoir des modifications de l'état de l'environnement d'exécution.
La présence d'un point de séquence entre l'évaluation des expressions A et B implique que chaque calcul de valeur et effet secondaire associé à A est séquencé avant chaque calcul de valeur et tout effet secondaire associé à B.
Voici la liste complète des points de séquence de l'annexe C du projet de publication préalable en ligne 2011 de la norme du langage C:
Points de séquence
1 Les points de séquence décrits au 5.1.2.3 sont les suivants:
- Entre les évaluations du désignateur de fonction et les arguments réels dans un appel de fonction et l'appel réel. (6.5.2.2).
- Entre les évaluations des premier et second opérandes des opérateurs suivants: ET logiques
&&
(6.5.13); OU logique||
(6.5.14); virgule,
(6.5.17).- Entre les évaluations du premier opérande du conditionnel
? :
opérateur et celui des deuxième et troisième opérandes sont évalués (6.5.15).- La fin d'un déclarateur complet: les déclarants (6.7.6);
- Entre l'évaluation d'une expression complète et la prochaine expression complète à évaluer. Les expressions suivantes sont des expressions complètes: un initialiseur qui ne fait pas partie d'un littéral composé (6.7.9); l'expression dans une expression (6.8.3); l'expression de contrôle d'une instruction de sélection (
if
ouswitch
) (6.8.4); l'expression de contrôle d'une instructionwhile
oudo
(6.8.5); chacune des expressions (facultatives) d'une déclarationfor
(6.8.5.3); l'expression (facultatif) dans une déclaration dereturn
(6.8.6.4).- Immédiatement avant qu'une fonction de bibliothèque ne retourne (7.1.4).
- Après les actions associées à chaque spécificateur de conversion de fonction d'entrée / sortie formaté (7.21.6, 7.29.2).
- Immédiatement avant et immédiatement après chaque appel à une fonction de comparaison, ainsi qu'entre tout appel à une fonction de comparaison et tout mouvement des objets transmis comme arguments à cet appel (7.22.5).
Expressions séquencées
Les expressions suivantes sont séquencées :
a && b
a || b
a , b
a ? b : c
for ( a ; b ; c ) { ... }
Dans tous les cas, l'expression a
est pleinement évaluée et tous les effets secondaires sont appliqués avant que b
ou c
soient évalués. Dans le quatrième cas, seul l'un des b
ou c
sera évalué. Dans le dernier cas, b
est entièrement évalué et tous les effets secondaires sont appliqués avant que c
soit évalué.
Dans tous les cas, l'évaluation de l'expression a
est séquencée avant les évaluations de b
ou c
(alternativement, les évaluations de b
et c
sont séquencées après évaluation de a
).
Ainsi, les expressions comme
x++ && x++
x++ ? x++ : y++
(x = f()) && x != 0
for ( x = 0; x < 10; x++ ) { ... }
y = (x++, x++);
avoir un comportement bien défini.
Expressions sans séquence
Les expressions suivantes ne sont pas séquencées :
a + b;
a - b;
a * b;
a / b;
a % b;
a & b;
a | b;
Dans les exemples ci-dessus, l'expression a
peut être évaluée avant ou après l'expression b
, b
peut être évaluée avant a
, ou même peuvent être mélangées si elles correspondent à plusieurs instructions.
Une règle similaire s'applique aux appels de fonction:
f(a, b);
Ici , non seulement a
et b
sont non séquencée ( par exemple la ,
l' opérateur dans un appel de fonction ne produit pas un point de séquence) , mais aussi f
, l'expression qui détermine la fonction qui doit être appelée.
Les effets secondaires peuvent être appliqués immédiatement après l'évaluation ou différés jusqu'à un stade ultérieur.
Des expressions comme
x++ & x++;
f(x++, x++); /* the ',' in a function call is *not* the same as the comma operator */
x++ * x++;
a[i] = i++;
ou
x++ & x;
f(x++, x);
x++ * x;
a[i++] = i;
va donner un comportement indéfini parce que
- une modification d'un objet et tout autre accès à celui-ci doit être séquencé
- l'ordre d'évaluation et l'ordre dans lequel les effets secondaires 1 sont appliqués ne sont pas spécifiés.
1 Toute modification de l'état de l'environnement d'exécution.
Expressions indéterminées
Les appels de fonction comme f(a)
impliquent toujours un point de séquence entre l'évaluation des arguments et l'indicatif (ici f
et a
) et l'appel réel. Si deux appels de ce type ne sont pas séquencés, les deux appels de fonction sont indéfiniment séquencés, c'est-à-dire que l'un est exécuté avant l'autre et que l'ordre n'est pas spécifié.
unsigned counter = 0;
unsingned account(void) {
return counter++;
}
int main(void) {
printf("the order is %u %u\n", account(), account());
}
Cette double modification implicite du counter
lors de l'évaluation des arguments printf
est valide, nous ne savons tout simplement pas lequel des appels vient en premier. Comme la commande n'est pas spécifiée, elle peut varier et ne peut pas être utilisée. L'impression pourrait donc être:
la commande est 0 1
ou
la commande est 1 0
La déclaration analogue à ce qui précède sans appel de fonction intermédiaire
printf("the order is %u %u\n", counter++, counter++); // undefined behavior
a un comportement indéfini car il n'y a pas de point de séquence entre les deux modifications du counter
.