web-dev-qa-db-fra.com

En C et C ++, est une expression utilisant l'opérateur virgule comme "a = b, ++ a;" indéfini?

Prenez ces trois extraits de code C:

1) a = b + a++
2) a = b + a; a++
3) a = b + a, a++

Tout le monde sait que l'exemple 1 est une très mauvaise chose et invoque clairement un comportement indéfini. L'exemple 2 n'a aucun problème. Ma question concerne l'exemple 3. L'opérateur virgule fonctionne-t-il comme un point-virgule dans ce type d'expression? 2 et 3 sont-ils équivalents ou 3 est-il aussi indéfini que 1?

Plus précisément, je réfléchissais à quelque chose comme free(foo), foo = bar. Il s'agit essentiellement du même problème que ci-dessus. Puis-je être sûr que foo est libéré avant d'être réaffecté, ou s'agit-il d'un problème de point de séquence clair?

Je suis conscient que les deux exemples sont largement inutiles et il est beaucoup plus logique d'utiliser simplement un point-virgule et d'en finir avec. Je demande juste par curiosité.

22
Roflcopter4

Le cas 3 est bien défini.

La section 6.5.17 de la norme C concernant l'opérateur de virgule , Dit ce qui suit:

2 L'opérande gauche d'un opérateur virgule est évalué comme une expression vide; il y a un point de séquence entre son évaluation et celle de l'opérande droit. Ensuite l'opérande droit est évalué; le résultat a son type et sa valeur

La section 5.14 p1 de la norme C++ 11 a un langage similaire:

Une paire d'expressions séparées par une virgule est évaluée de gauche à droite; l'expression de gauche est une expression de valeur rejetée. Chaque calcul de valeur et effet secondaire associé à l'expression gauche est séquencé avant chaque calcul de valeur et effet secondaire associé à l'expression droite. Le type et la valeur du résultat sont le type et la valeur de l'opérande droit; le résultat est de la même catégorie de valeur que son opérande droit, et est un champ binaire si son opérande droit est une valeur gl et un champ binaire.

En raison du point de séquence, a = b + a Est garanti d'être pleinement évalué avant a++ Dans l'expression a = b + a, a++.

En ce qui concerne free(foo), foo = bar, cela garantit également que foo est libéré avant qu'une nouvelle valeur ne soit affectée.

38
dbush

a = b + a, a++; Est bien défini, mais a = (b + a, a++); peut être indéfini.

Tout d'abord, la priorité de l'opérateur rend l'expression équivalente à (a = (b+a)), a++;, Où + A la priorité la plus élevée, suivi de =, Suivi de ,. L'opérateur virgule inclut un point de séquence entre l'évaluation de son opérande gauche et droit. Le code est donc, sans intérêt, complètement équivalent à:

a = b + a;
a++;

Ce qui est bien sûr bien défini.


Si nous avions plutôt écrit a = (b + a, a++);, le point de séquence dans l'opérateur virgule ne sauverait pas le jour. Car alors l'expression aurait été équivalente à

(void)(b + a);
a = a++;
  • En C et C++ 14 ou plus, a = a++ N'est pas séquencé (voir C11 6.5.16/3). Cela signifie qu'il s'agit d'un comportement indéfini (selon C11 6.5/2). Notez que C++ 11 et C++ 14 étaient mal formulés et ambigus.
  • En C++ 17 ou version ultérieure, les opérandes de l'opérateur = Sont séquencés de droite à gauche et cela est toujours bien défini.

Tout cela en supposant qu'aucune surcharge d'opérateur C++ n'ait lieu. Dans ce cas, les paramètres de la fonction d'opérateur surchargée seront évalués, un point de séquence a lieu avant l'appel de la fonction, et ce qui en résulte dépend des internes de cette fonction.

11
Lundin