128 votes

Pourquoi cet extrait de code C ++ est-il compilé (la fonction non-vide ne renvoie pas de valeur)

J'ai trouvé ça dans une de mes bibliothèques de ce matin:

static tvec4 Min(const tvec4& a, const tvec4& b, tvec4& out)
{
    tvec3::Min(a,b,out);
    out.w = min(a.w,b.w);
}

Je m'attends à une erreur de compilation, car cette méthode ne retourne rien, et le type de retour n'est pas void.

Les deux seules choses qui me vient à l'esprit sont

  • Dans le seul endroit où cette méthode est appelée, la valeur de retour n'est pas utilisé ou stocké. (Cette méthode a été censé être void - tvec4 type de retour est un copier-coller de l'erreur)

  • un défaut construits tvec4 est en cours de création, ce qui semble un peu à la différence, oh, tout le reste en C++.

Je n'ai pas trouvé la partie du C++ spec qui porte sur cette question. Références (ha) sont appréciés.

Mise à jour

Dans certaines circonstances, cela génère une erreur dans VS2012. Je n'ai pas rétréci vers le bas les détails, mais c'est intéressant, néanmoins.

155voto

Shafik Yaghmour Points 42198

C'est un comportement indéfini du C++11 projet de norme section 6.6.3 L'instruction de retour de l'alinéa 2 qui dit:

[...] Qui coule à la fin d'une fonction est l'équivalent d'un retour sans valeur; il en résulte un comportement non défini dans la valeur de retour de la fonction. [...]

Cela signifie que le compilateur n'est pas obligé de fournir un message d'erreur ni avertissement généralement parce qu'il peut être difficile à diagnostiquer dans tous les cas. Nous pouvons le voir à partir de la définition d' un comportement non défini dans le projet de norme dans la section 1.3.24 qui dit:

[...]Admissible comportement indéfini plages d'ignorer la situation complètement avec des résultats imprévisibles, à se comporter lors de la traduction ou de l'exécution du programme dans documenté de façon caractéristique de l'environnement (avec ou sans émission d'un message de diagnostic), à la terminaison d'une traduction ou d'exécution (avec l'émission d'un message de diagnostic).[...]

Bien que dans ce cas, nous pouvons obtenir à la fois gcc et clang pour générer un wanring à l'aide de l' -Wall drapeau, ce qui me donne un avertissement similaire à ceci:

avertissement: le contrôle a atteint sa fin de non-void function [-Wreturn-type]

Nous pouvons nous tourner ce message d'avertissement dans une erreur à l'aide de l' -Werror=return-type drapeau. J'aime également utiliser -Wextra -Wconversion -pedantic pour mes propres projets personnels.

Comme ComicSansMS mentionne dans Visual Studio , le code pourrait générer C4716 qui est une erreur par défaut, le message que je vois est:

erreur C4716: "Min": doit retourner une valeur

et dans le cas où tous les chemins de code doit retourner une valeur, alors il serait de générer des C4715, qui est un avertissement.

58voto

ComicSansMS Points 12749

Peut-être quelques explications sur le pourquoi de la partie de la question:

Comme il s'avère, il est effectivement assez difficile pour un compilateur C++ pour déterminer si une fonction se termine sans valeur de retour. Outre les chemins de code que fin en retour explicite des états et de ceux qui tombent à la fin de la fonction, vous devez également tenir compte de la possibilité exception lance ou longjmps dans la fonction elle-même, ainsi que l'ensemble de ses fonctions appelées.

Alors qu'il est assez facile pour un compilateur pour identifier une fonction qui ressemble, c'est peut-être manquant un retour, il est beaucoup plus difficile de prouver qu'il manque un retour. Afin d'aider les éditeurs de compilateurs de ce fardeau, le standard n'a pas besoin de cela pour générer une erreur.

Donc, compilateur, les vendeurs sont libres de produire un avertissement si ils sont tout à fait sûr qu'une fonction manque de retour et que l'utilisateur est libre de l'ignorer/masque d'avertissement dans les rares cas où le compilateur a fait mal.

22voto

Nawaz Points 148870

Compiler votre code avec -Wreturn-type option:

$ g++ -Wreturn-type source.cpp

Cela vous donnera l' alerte. Vous pouvez activer l'alerte d'erreur si vous utilisez -Werror trop:

$ g++ -Wreturn-type -Werror source.cpp

Notez que cela fera tourner toutes les mises en garde sur les erreurs. Donc, si vous voulez d'erreur pour l'avertissement spécifique, disons -Wreturn-type, il suffit de taper return-type sans -W partie:

$ g++ -Werror=return-type source.cpp

En général, vous devriez toujours utiliser -Wall option qui comprend la plupart des avertissements communs — ce qui inclut manquant instruction de retour également. Avec -Wall, vous pouvez utiliser -Wextra également, qui comprend d'autres mises en garde n'ont pas inclus l' -Wall.

22voto

Jirka Hanika Points 8266

Peut-être que certains d'autres precisions sur le pourquoi de la partie de la question.

C++ a été conçu de sorte qu'un très grand corps de pré-corps de C code compile avec le minimum de modifications. Malheureusement, C lui-même était en train de payer un droit similaire à la première pré-standard C, qui n'ont même pas de l' void mot-clé et s'est plutôt appuyée sur une valeur par défaut type de retour d' int. C fonctions d'habitude les valeurs de retour, et chaque fois que le code superficiellement similaire à Algol/Pascal/procédures de Base a été écrit sans aucune return états, la fonction a été, sous le capot, le retour selon les ordures laissées sur la pile. Ni l'appelant ni le destinataire de l'appel affecte la valeur de la poubelle d'une façon fiable. Si la poubelle est alors ignoré par tous les appelant, tout est beau et C++ hérite de l'obligation morale de les compiler le code.

(Si la valeur retournée est utilisé par l'appelant, le code peut avoir un comportement non déterministe, comme pour le traitement d'une variable non initialisée. Pourrait la différence être identifiés de manière fiable par un compilateur, dans un hypothétique successeur du langage C? Ce n'est guère possible. L'appelant et l'appelé peut-être dans les différentes unités de compilation.)

L'implicite int n'est qu'une partie de l'héritage en cause ici. Un "répartiteur" fonction peut, en fonction d'un paramètre, de retour d'une variété de types de certaines branches de code, et de ne renvoyer aucune valeur d'utilité des autres branches de code. Une telle fonction serait généralement être déclarée pour retourner un type assez long pour contenir tous les types possibles et l'appelant peut-être besoin de le jeter ou de l'extraire à partir d'un union.

Donc, la cause la plus profonde est probablement le langage C créateurs croyance que les procédures qui ne retourne pas de valeur sont juste un peu d'importance du cas particulier de fonctions; ce problème a aggravées par le manque de focalisation sur la sécurité du type d'appels de fonction dans le plus vieux C dialectes.

Tandis que le C++ n'a casser la compatibilité avec certains des pires aspects de C (exemple), la volonté de compiler une instruction de retour sans valeur (ou la valeur implicite retour à la fin de la fonction) n'était pas l'un d'eux.

12voto

Zac Howland Points 12204

Comme déjà mentionné, il s'agit d'un comportement indéfini qui vous avertira du compilateur. La plupart des endroits sur lesquels j'ai travaillé exigent que vous activiez les paramètres du compilateur pour traiter les avertissements comme des erreurs - ce qui impose que tout votre code soit compilé avec 0 erreurs et 0 avertissements. C'est un bon exemple de pourquoi c'est une bonne idée.

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