8
votes

C ++ applique-t-il des déclarations de retour?

D'accord, petite bizarrerie que j'ai découverte avec mon compilateur C ++.

J'ai eu un peu trop complexe de code dans le refacteur, et j'ai accidentellement réussi à laisser dans un chemin qui n'avait pas de déclaration de retour. Ma faute. D'autre part, cela compilé, et segfaulés quand je l'ai couri et que ce chemin a été frappé, évidemment.

Voici ma question: est-ce un bogue de compilateur ou ne garantit-il aucune garantie qu'un compilateur C ++ appliquera la nécessité d'une déclaration de retour dans une fonction de retour non annulée?

OH, et être clair, dans ce cas, ce fut une déclaration inutile sans un accompagnateur d'autre. Pas de gotos, pas de sorties, pas d'abandon.


3 Réponses :


13
votes

Il n'y a aucune garantie qu'un compilateur C ++ appliquera cela. Une fonction C ++ pourrait sauter de son flux de contrôle par des mécanismes inconnus du compilateur. Commutateurs de contexte Lorsque C ++ est utilisé pour écrire un noyau OS est un exemple de cela. Une exception non capturée projetée par une fonction appelée (dont le code n'est pas nécessairement disponible pour l'appelant) en est un autre.

Certaines autres langues, telles que Java, appliquent explicitement qu'avec des connaissances disponibles au moment de la compilation, tous les chemins renvoient une valeur. En C ++, ce n'est pas vrai, comme cela est avec beaucoup d'autres occasions dans la langue, comme l'accès à un tableau hors de ses limites n'est pas vérifié non plus.


14 commentaires

"Une fonction C ++ pourrait sauter de son flux de contrôle par des mécanismes inconnus du compilateur." - Oui, mais le flux sera sauté dans. Un interrupteur de contexte se retourne, après tout. Je ne vois vraiment pas ce que cela a à voir avec les valeurs de retour. Le seul cas, la fonction ne sera pas retournée est si une exception est lancée.


@Neil pas nécessaire. Un appel à Quitter , par exemple, ne sauverra jamais.


@Johannes OK, et avortez () et terminez (). Mais le compilateur ne peut pas voir que celles-ci annule la nécessité d'un retour, à moins que cela ne traite comme "spécial" d'une certaine manière.


@Neil exactement. C'est pourquoi il ne peut pas vous faire respecter de retourner une valeur, car elle ne sait pas qu'ils nient la nécessité d'un retour, comme vous l'avez parfaitement remarqué. Il suppose que cela ne vous retourne pas et ne vous fait pas confiance.


@Johannes sur les très rares occasions qui sortent / avortez / interrompent sont appelées (je ne pense pas avoir appelé l'un d'entre eux dans ma carrière), je dirais avoir à ajouter une "fausse" déclaration de retour est préférable à l'alternative Ne pas diagnostiquer des déclarations de retour manquantes, ce qui est un problème beaucoup plus commun.


@LitB: omg, pourquoi? Il applique régulièrement des invariants sur des chemins impossibles dans le code, pourquoi ne pourrait-il pas imposer de retourner une valeur, même lorsque Coude ne serait jamais utilisé? Voir Ideone.com/mhdkl


@Neil, eh bien je suis d'accord avec vous entière degré. Dans mon propre animal de compagnie, je l'appliquerais aussi. Mais il semble que C et C ++ soient le genre de langage qui ne se souciait pas de cela.


@jpalecek Il me semble que le problème "goto" est facilement corrigé en enveloppant un bloc autour de la déclaration de variable. Dans le cas de la fonction, ajouter un "retour quelqueévaleur"; Calculer peut-être le code généré par une marge (pas ce que les principes de conception C et C ++ 'sont cible). Je soupçonne que l'intention du C ++ Les gars était que les gens puissent ajouter un "avortement ();" Impossible de prendre des chemins, au lieu d'un retour factice (que j'essaie personnellement d'éviter, parce que c'est du code mort).


@Johannes tandis que j'ai votre attention, sur une question quelque peu tangentiellement liée, avez-vous vu cette question Stackoverflow.com/questions/3179494/... - avez-vous lu comment les signaux affectent les vies d'objets ?


@Johannes j'ai raté cela, mais cela semble un peu, dirons-nous, équivoque. Avez-vous une référence standard C ++ pour cela? Peut-être rouvrir la réponse dans ce fil?


@Neil Voir 18,7 et 3.6.3 / 4 (et 18.3 / 3).


@jpalecek: Il est facile de renvoyer un mannequin int . Mais si une fonction retourne un type beaucoup plus complexe? Vous ne pouvez pas en général supposer que cela est même possible de créer un objet factice. Même là où vous pouvez, cela peut impliquer d'écrire beaucoup de code. Ou vous vous retrouvez avec un * (t *) null hack. Vraiment, cela n'améliore rien sur un retour manquant.


Je soupçonne qu'au lieu d'un "retour" de fin, ils pouvaient également accepter un "lancer" traînant. Cela ne nécessiterait pas de simuler un t en faisant * (t *) 0 ou quelque chose.


@Msalters: Je fais habituellement jet de 0; ou quelque chose comme ça dans ce cas, comme le suggère le LitB.



4
votes

Le compilateur ne l'applique pas parce que vous avez des connaissances sur les chemins de route sont pratiquement possibles que le compilateur ne le fait pas. Le compilateur ne connaît généralement que ce fichier particulier, pas d'autres personnes pouvant affecter le flux à l'intérieur d'une fonction donnée. Donc, ce n'est pas une erreur.

dans Visual Studio, cependant, c'est un avertissement. Et nous devrions faire attention à tous les avertissements ... oui? :)

edit : Il semble y avoir une discussion sur quand cela pourrait arriver. Voici un exemple modifié mais réel de ma bibliothèque de code personnelle; xxx

supporte avec moi parce que c'est un code ancien. Initialement, il y avait un "autre retour peut-être" là-bas. :) Si Testone et TestTwo sont dans une unité de compilation différente, alors lorsque le compilateur frappe ce code, il ne peut pas indiquer si Testone et TestTwo pourrait tous les deux renvoyer false pour une entrée donnée. En tant que programmeur qui écrivait Testone et TestTwo, sachez que si Testone échoue, TestTwo réussira. Peut-être qu'il y a des effets secondaires de ces tests afin qu'ils doivent être effectués. Serait-il préférable de l'écrire sans le "autre si"? Peut-être. Probablement. Mais le point est que c'est légal C ++ et le compilateur ne peut pas savoir s'il est possible de quitter sans déclaration de retour. C'est, je suis d'accord, maidly et pas bon codage, mais c'est un studio légal et visuel vous donnera un avertissement, mais cela compilera.

N'oubliez pas que C ++ n'est pas de vous protéger de vous-même. Il s'agit de vous laisser faire ce que votre cœur désire dans les contraintes de la langue, même si cela inclut vous tirer dessus au pied.


5 commentaires

Cela n'a aucun sens. Le compilateur Musty a connaissance de quels chemins sont possibles afin de compiler le code.


@Neil je pense qu'il a un point. Le compilateur ne sait pas toujours à Compiler Heure . Comme si vous n'aviez aucune idée lorsque vous avez posté votre commentaire, je posterais une réponse à elle. Mais maintenant, vous savez, et éventuellement avoir des précautions pour répondre à leur tour ou non. Ou vous êtes totalement surpris, comme le C ++ sera, et faire des choses indéfinies :)


C'est un non-sens IMHO. Le graphe de contrôle de toute fonction donnée est parfaitement connu par le compilateur après avoir analysé son code. Il serait peut-être nécessaire que certains bords ne soient jamais traversés lors de l'exécution du code (réfléchir aux affirmations), mais le compilateur traite de cela en tant que tel et que tout ce qu'il cause n'est qu'une supposition (trop) conservatrice.


Le test du compilateur doit-il être réel toutes les entrées possibles pour le code? Donc, en effet à la compilation, il ne peut pas savoir, pour tous les "chemins", qui peuvent être pris et qui ne peuvent pas. Donc, il y a des cas où il ne peut pas être capable d'identifier "un chemin" qui se termine sans aucun résultat de retour? Je dois encore imaginer qui sont ces cas, cependant.


-1: Je suis d'accord avec @jpalecek et anon. Ceci est non-sens: le compilateur peut toujours déterminer si un code manque de déclaration de retour. C'est en fait ce que GCC fait avec -wreturn-type . Ce qu'il ne peut pas comprendre, d'autre part, sont des moyens qui ne seront jamais atteints. @ Johannesschab-LitB: un compilateur ne fonctionne que sur Compilation Time et le lien de liaison ne traitera pas des flux de code lorsque tout le matériel qu'il a est un code de machine.



13
votes

Personnellement, je pense que cela devrait être une erreur: xxx

Mais la plupart des compilateurs le traitent comme un avertissement, et vous pouvez même avoir à utiliser des commutateurs de compilateur pour obtenir cet avertissement. Par exemple, sur g ++, vous avez besoin -wall pour obtenir: xxx

bien sûr, avec g ++, vous devez toujours compiler avec au moins -wall quand même.


0 commentaires