Comme je l'ai écrit dans une réponse à Comment est-il possible d'utiliser pow sans inclure la bibliothèque cmath ? Je crains d'avoir prouvé que l'absence d'inclusion d'un en-tête nécessaire est en fait un comportement non défini, mais comme je n'ai trouvé aucun consentement de ce fait, j'aime imposer la question formelle :
Il manque un en-tête obligatoire, par exemple
#include <iostream>
int main()
{
std::cout << std::pow(10, 2);
}
- Un code mal formé ([defns.ill.formed]) ?
- Invoquer un comportement non défini ( [defns.undefined] ) ?
- Si ce n'est pas 1 et 2, s'agit-il d'un comportement non spécifié [defns.unspecified] ou d'un comportement défini par l'implémentation [defns.impl.defined] ?
- Si ce n'est pas 1, c'est-à-dire si ce code est bien formé, cela ne contredirait-il pas [using.headers] et [intro.compliance] "accepter et exécuter correctement un programme bien formé" ?
Comme dans mon réponse J'ai tendance à répondre par l'affirmative à ces deux questions, mais [using.headers] est très déroutant à cause de Différence entre un comportement non défini et un comportement mal formé, pas de message de diagnostic nécessaire . Comme [defns.well.formed] implique qu'un programme construit selon l'ODR est bien formé, et qu'il y a une spécification de chaque fois que le par exemple iostream
ne doit pas définir pow
On pourrait dire qu'il s'agit toujours d'un comportement non spécifié ([defns.unspecified]). Je ne veux pas me fier uniquement à mes compétences en matière d'interprétation standard pour obtenir une réponse définitive à une question aussi importante. Notez que la réponse acceptée, c'est-à-dire la seule autre réponse, ne permet pas de savoir si le code est UB et la question ne le demande pas.
1 votes
Il est possible que vous souhaitiez remplacer ce texte par
std::cout << std::pow(10.0, 2.0);
0 votes
Il devrait s'agir d'une erreur au moment de la compilation. Il manque également
using namespace std;
ouusing std::pow
.2 votes
@LuketheGeek Une erreur de compilation n'exclut pas l'UB. Et MSVC semble toujours se conformer à la norme en ne lançant pas d'erreur mais en compilant simplement.
1 votes
Vous êtes probablement dans le domaine de "...comportement défini par l'implémentation..." . Fichiers d'en-tête peut inclure d'autres fichiers d'en-tête, mais ce n'est pas obligatoire. Ainsi, votre programme peut se compiler sur un système mais pas sur un autre. Voir aussi : fr.cppreference.com/w/cpp/language/ub
0 votes
@RichardCritten J'y ai pensé, mais la mise en œuvre d'un comportement défini nécessite un programme bien formé.
1 votes
Il s'agit d'un programme bien conçu, mais uniquement sur votre système. Il semble que <iostream> inclut <cmath> (directement ou indirectement)
0 votes
@RichardCritten N'est-ce pas là la définition de l'UB ?
0 votes
@Superlokkus "N'est-ce pas la définition de l'UB ?" Non. Vous dépendez des inclusions transitives. C'est la mise en œuvre définie comportement, et non indéfini comportement. Tant que l'implémentation finit par inclure tout ce dont vous avez besoin, tout va bien. Vous ne pouvez pas compter sur cela sans inclure explicitement ce dont vous avez besoin vous-même.
0 votes
Si tous les fichiers d'en-tête sont inclus, il n'y a pas d'UB. Si, sur un autre système, les fichiers d'en-tête ne sont pas inclus les uns dans les autres, vous avez (sur ce système) une mal formé programme. Il n'y a pas d'UB.
0 votes
@JesperJuhl J'y ai pensé aussi : Si c'était vrai, MSVC serait en violation du standard, puisque [defns.impl.defined] requiert de la documentation, et que la bibliothèque standard de MSVC ne documente pas qu'elle inclut cmath, même de manière transitoire.
1 votes
Il n'est pas obligé de le faire, il doit seulement vous indiquer quel est l'en-tête correct à inclure.
<cmath>
. Le fait que vous ne le fassiez pas ne signifie pas que l'EM ne se conforme pas à la norme,0 votes
@RichardCritten Sur un système où l'en-tête ne l'inclut pas, cela violerait l'ODR, qui stipule qu'une violation de l'ODR implique l'UB.
0 votes
@Superlokkus Les fichiers d'en-tête sont publics (et, depuis peu, toute la bibliothèque standard), on pourrait dire que cela compte comme de la documentation - vous pouvez lire et voir ce qui est inclus.
1 votes
Le programme échouerait simplement à la compilation (définition manquante) et il n'y aurait donc pas de violation de l'ODR.
0 votes
@RichardCritten Selon quel paragraphe de la norme un diagnostic est-il nécessaire ? Recherche de nom ?
0 votes
Cela ne signifierait-il pas que le code est mal formé mais que, grâce à [using.headers], aucun diagnostic n'est nécessaire, MSVC est toujours conforme à la norme ?
0 votes
Exemple concret - godbolt.org/z/6cB3Pd
0 votes
Un comportement non défini signifie qu'une même exécution PEUT avoir plusieurs comportements. Ici vous êtes au niveau COMPILE, votre programme compilera et liera TOUJOURS de la même manière. vous aurez toujours les mêmes binaires. avec un en-tête manquant vous pouvez : avoir une erreur de compilation, utiliser un autre espace de noms, désactiver l'option de compilation, ... mais le comportement COMPILE est défini.
0 votes
@RichardCritten Je sais qu'il compile et fonctionne sous MSVC, ce n'est pas la question.
0 votes
@Landstalker Je pense que vous avez décrit [defns.unspecified] qui exclut UB dans mon sous-entendu.
0 votes
@Superlokkus voir les 2 autres compilateurs diagnostiquer le problème.
0 votes
@RichardCritten D'une autre manière : Si ce code n'est pas UB, et n'est pas une violation de l'ODR, il n'est pas mal formé, ce qui signifierait par définition, bien formé et les implémentations devraient l'accepter. i.e. 4.1.2.1 n'est pas == UB ?