98 votes

Quelle est la bonne réponse pour cout << c++ << c; ?

Récemment, lors d'un entretien, une question de type objectif a été posée.

int c = 0;
cout << c++ << c;

Des réponses :

a. 10
b. 01
c. un comportement indéfini

J'ai répondu au choix b, c'est-à-dire que la sortie serait "01".

Mais à ma grande surprise, un intervieweur m'a dit plus tard que la bonne réponse était l'option c : indéfinie.

Maintenant, je connais le concept de points de séquence en C++. Le comportement est indéfini pour l'instruction suivante :

int i = 0;
i += i++ + i++;

mais selon ma compréhension de la déclaration cout << c++ << c le ostream.operator<<() serait appelé deux fois, d'abord avec ostream.operator<<(c++) et plus tard ostream.operator<<(c) .

J'ai également vérifié le résultat avec le compilateur VS2010 et sa sortie est également '01'.

144voto

Maxim Yegorushkin Points 29380

Vous pouvez y penser :

cout<<c++<<c;

En tant que :

std::operator<<(std::operator<<(std::cout, c++), c);

C++ garantit que tous les effets secondaires des évaluations précédentes auront été réalisés à points de séquence . Il n'y a pas de points de séquence entre l'évaluation des arguments de la fonction, ce qui signifie que l'argument c peut être évalué avant l'argument std::operator<<(std::cout, c++) ou après. Le résultat de ce qui précède est donc indéfini.

68voto

Alok Save Points 115848

Techniquement, globalement, c'est Comportement indéfini .

Mais, il y a deux aspects importants à la réponse.

L'énoncé du code :

std::cout<<c++<<c;

est évalué comme :

std::operator<<(std::operator<<(std::cout, c++), c);

La norme ne définit pas l'ordre d'évaluation des arguments d'une fonction.
Soit :

  • std::operator<<(std::cout, c++) est évalué en premier ou
  • c est évalué en premier ou
  • il peut s'agir de n'importe quel ordre défini par la mise en œuvre.

Cet ordre est Non spécifié [Réf. 1] conformément à la norme.

[Réf. 1] C++03 5.2.2 Appel de fonction
Para 8

L'ordre d'évaluation des arguments n'est pas spécifié. . Tous les effets secondaires des évaluations des expressions arguments prennent effet avant l'entrée de la fonction. L'ordre d'évaluation de l'expression postfixe et de la liste des expressions d'arguments n'est pas spécifié.

De plus, il n'y a pas de point de séquence entre l'évaluation des arguments d'une fonction, mais un point de séquence n'existe qu'après l'évaluation de tous les arguments. [Réf. 2] .

[Réf. 2] C++03 1.9 Exécution du programme [intro.execution] :
Para 17 :

Lors de l'appel d'une fonction (que la fonction soit en ligne ou non), il y a un point de séquence après l'évaluation de tous les arguments de la fonction (le cas échéant) qui a lieu avant l'exécution de toute expression ou instruction dans le corps de la fonction.

Notez que, ici, la valeur de c est accédé plus d'une fois sans point de séquence intermédiaire, la norme précise à ce sujet que

[Réf. 3] C++03 5 Expressions [expr] :
Para 4 :

....
Entre le point de séquence précédent et le suivant, la valeur stockée d'un objet scalaire doit être modifiée au maximum une fois par l'évaluation d'une expression. En outre, la valeur précédente ne doit être consultée que pour déterminer la valeur à stocker. . Les exigences du présent paragraphe doivent être satisfaites pour chaque ordre admissible des sous-expressions d'une expression entière complète ; sinon le comportement est indéfini .

Le code modifie c plus d'une fois sans point de séquence intermédiaire et on n'y accède pas pour déterminer la valeur de l'objet stocké. Il s'agit d'une violation évidente de la clause ci-dessus et le résultat, tel qu'exigé par la norme, est le suivant Comportement indéfini [Réf. 3] .

19voto

James Kanze Points 96599

Les points de séquence définissent uniquement une partiel de commande. Dans votre cas, vous avez (une fois la résolution des surcharges effectuée) :

std::cout.operator<<( c ++ ).operator<<( c );

Il y a un point de séquence entre le c ++ et le premier appel à std::ostream::operator<< et il y a un point de séquence entre le deuxième c et le deuxième appel à std::ostream::operator<< mais il n'y a pas il n'y a pas de point de séquence entre c ++ et c les seules contraintes d'ordre contraintes sont que c ++ être entièrement évalué (y compris les effets secondaires) avant le premier appel à operator<< et que le second c être entièrement avant le deuxième appel à operator<< . (Il existe également contraintes d'ordre causal : le deuxième appel à la fonction operator<< ne peut pas précédent le premier, puisqu'il requiert les résultats du premier en tant qu'argument. argument). Le §5/4 (C++03) stipule :

Sauf indication contraire, l'ordre d'évaluation l'ordre d'évaluation des opérandes des opérateurs individuels et des sous-expressions des expressions individuelles, et l'ordre dans lequel les effets secondaires ont lieu, ne sont pas spécifiés. Entre le point de séquence précédent et le suivant, un objet scalaire a sa valeur stockée modifiée au plus une fois par l'évaluation d'une expression. l'évaluation d'une expression. De plus, la valeur précédente ne doit être accessible uniquement pour déterminer la valeur à stocker. Les exigences du de ce paragraphe doivent être respectées pour chaque ordre autorisé des des sous-expressions d'une expression complète ; sinon, le comportement est indéfini.

L'un des ordres possibles de votre expression est le suivant c ++ , c premier appel à operator<< , deuxième appel à operator<< ; cela modifie la valeur stockée de c ( c ++ ), et y accède autrement que pour déterminer la nouvelle valeur (la deuxième c ), le comportement est indéfini.

4voto

Paul Marrington Points 161

La réponse correcte est de poser la question. L'énoncé est inacceptable parce qu'un lecteur ne peut y voir une réponse claire. Une autre façon de voir les choses est que nous avons introduit des effets secondaires (c++) qui rendent la déclaration beaucoup plus difficile à interpréter. Un code concis est excellent, à condition que sa signification soit claire.

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