Maison > développement back-end > C++ > Le chaînage de fonctions dans « Le langage de programmation C » présente-t-il un comportement non spécifié ?

Le chaînage de fonctions dans « Le langage de programmation C » présente-t-il un comportement non spécifié ?

Barbara Streisand
Libérer: 2024-10-23 18:19:25
original
456 Les gens l'ont consulté

Does Function Chaining in

Un extrait de code dans "Le langage de programmation C" présente-t-il un comportement non défini ?

Le code C en question, tel que fourni par Bjarne Stroustrup dans la 4e édition de " Le langage de programmation C" utilise le chaînage de fonctions pour modifier une chaîne :

<code class="cpp">void f2() {
    std::string s = "but I have heard it works even if you don't believe in it";
    s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, "");

    assert(s == "I have heard it works only if you believe in it");
}</code>
Copier après la connexion

Ce code démontre le chaînage des opérations replace() pour modifier la chaîne s. Cependant, il a été observé que ce code présente un comportement différent selon les différents compilateurs, tels que GCC, Visual Studio et Clang.

Analyse

Bien que le code puisse paraître simple, il implique un ordre non spécifié d'évaluation, en particulier pour les sous-expressions qui impliquent des appels de fonction. Bien qu'il n'invoque pas de comportement indéfini (puisque tous les effets secondaires se produisent dans les appels de fonction), il présente un comportement non spécifié.

Le problème clé est que l'ordre d'évaluation des sous-expressions, telles que s.find( "even") et s.find(" don't"), n'est pas explicitement défini. Ces sous-expressions peuvent être évaluées avant ou après l'appel initial à s.replace(0, 4, ""), ce qui peut avoir un impact sur le résultat.

Si nous examinons l'ordre d'évaluation de l'extrait de code :

s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, "");
Copier après la connexion

On peut voir que les sous-expressions suivantes sont séquencées de manière indéterminée (indiquées par les chiffres entre parenthèses) :

  • s.replace(0, 4, "") (1)
  • s.find("even") (2)
  • s.replace(s.find("even"), 4, "seulement") (3)
  • s.find("ne pas") (4)
  • s.replace(s.find("ne pas"), 6, "") (5)

Les expressions contenues dans chaque paire de parenthèses sont ordonnées (par exemple, 2 précède 3), mais elles peuvent être évaluées dans des ordres différents les unes par rapport aux autres. Plus précisément, l'indétermination se situe entre les expressions 1 et 2, ainsi qu'entre 1 et 4.

Différences entre les compilateurs

Les écarts observés dans le comportement du compilateur peuvent être attribués aux différents ordres d'évaluation choisis par chacun compilateur. Dans certains cas, les appels à replace() sont évalués d'une manière qui aboutit au comportement attendu, tandis que dans d'autres cas, l'ordre d'évaluation modifie la chaîne de manière inattendue.

Pour illustrer, considérons ce qui suit :

  • Dans certaines implémentations, telles que Clang, replace(0, 4, "") est évalué avant find("even") et find(" don't"). Cela garantit que les appels de remplacement suivants fonctionnent sur la chaîne modifiée, produisant le résultat correct.
  • Dans d'autres implémentations, telles que GCC et Visual Studio, find("even") et find(" don't") peut être évalué avant replace(0, 4, ""). Cela peut conduire à des résultats incorrects, car les appels de recherche opèrent sur la chaîne d'origine non modifiée, trouvant potentiellement des positions différentes de celles prévues.

Comportement spécifié ou non spécifié

Il est important de noter que ce code n'invoque pas un comportement indéfini. Un comportement non défini implique généralement l'accès à des variables non initialisées ou la tentative d'accès à la mémoire en dehors de ses limites. Dans ce cas, tous les effets secondaires se produisent dans les appels de fonction et le code n'accède pas aux emplacements mémoire non valides.

Cependant, le code présente un comportement non spécifié, ce qui signifie que l'ordre exact de l'évaluation des sous-expressions n'est pas définie par le standard C. Cela peut conduire à des résultats différents selon les compilateurs ou même à différentes exécutions du même programme.

Modifications proposées

Le comité de standard C a reconnu ce problème et a proposé des modifications pour affiner l'ordre d'évaluation des expressions pour idiomatique C. Les modifications proposées pour [expr.call]p5 dans C 20 spécifient que "l'expression postfixée est séquencée avant chaque expression de la liste d'expressions et tout argument par défaut", ce qui éliminerait le comportement non spécifié dans ce code.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal