De nombreux mois de retour, j'ai dû réparer un code qui a provoqué des problèmes. Le code a été fondamentalement comme celui-ci: P>
Cela a évidemment provoqué un débordement de pile, même dans la langue de haut niveau, je travaillais avec (4Test en Silktest). Il n'y a aucun moyen que ce code puisse être considéré comme bénéfique. Le premier signe de problèmes étaient des avertissements observés après la fin du script, mais aucune erreur de compilation ni avertissements. Curieusement, j'ai essayé d'écrire des programmes en C ++, C # et Python avec la même structure, et tous compilés / interprétés sans erreurs de syntaxe ni avertissements, même à travers des erreurs d'exécution dans tous les cas. Je n'ai même pas vu d'avertissements dans aucun de ces cas. Pourquoi cela n'est-il pas vu comme un problème possible par défaut? p>
Edit: J'ai essayé d'écrire l'équivalent de cette fonction dans les trois langues, alors j'ai ajouté ces étiquettes de fonction. Je suis plus intéressé par des raisons générales pour lesquelles le code comme celui-ci ne traverse aucun avertissement. S'il vous plaît ralloner si nécessaire. P> int badfun () {retour badfun (); } code> p>
7 Réponses :
Parce que le compilateur ne vérifiera pas ce genre de choses. P>
Si vous installez un analyseur de code comme resharper code> dans Visual Studio CODE> Il apporte un avertissement d'appel récursif infini ou de la STH de la sorte au cas où vous avez activé l'option d'analyse de code. < / p>
Pourquoi cela n'est-il pas vu comme problème par défaut? P>
L'erreur est une erreur de temps d'exécution, pas une erreur d'heure de compilation. Le code est parfaitement valide, il fait quelque chose de stupide. Le cas très simple que vous montrez pourrait certainement être détecté, mais de nombreux cas qui seraient légèrement plus compliqués seraient difficiles à détecter: p>
xxx pré> afin de déterminer si c'est un Problème, le compilateur doit essayer de déterminer si la condition sera toujours vraie ou non. Dans le cas général, je ne pense pas que cela soit plus calculable que de déterminer si le programme finira par arrêter (c'est-à-dire qu'il est
Protrement pas calculable ). P> blockQquote>
+1. Les compilateurs ne se dérangent pas parce que le problème d'arrêt est insuffisant dans le cas général.
Par la même logique, un compilateur ne se soucierait pas à avertir du code inaccessible. Et pourtant, il fait - dans un sous-ensemble particulier de cas.
@Harold comme Eric Lippert a expliqué joliment une décision à une décision sur le coût et le bénéfice de la production de l'avertissement. Ce que j'essayais de dire ici, c'est que la détection de l'affaire triviale ne semble pas très utile et les cas non-attrapés où un avertissement serait utile risquait d'être difficile ou impossible à détecter.
Je doute que le compilateur puisse détecter un phénomène d'exécution (débordement de pile) au moment de la compilation. Il existe de nombreux cas valables pour appeler une fonction à l'intérieur de lui-même, à la récursivité. Mais comment le compilateur peut-il savoir le bien des mauvaises cas de récursivité? p>
Sauf si cela a été ajouté de l'AI, je ne pense pas qu'un compilateur pouvait détecter les différences entre la bonne et la mauvaise récursion, c'est le travail d'un programmeur. P>
Comment le compilateur ou l'interprète est-il supposé savoir quelle est la fonction? La portée du compilateur et de l'interprète est de compiler ou d'interpréter le code syntaxique - ne pas interpréter la sémantique de votre code. P>
Même si un compilateur vérifie cela, où dessinez-vous la ligne? Et si vous aviez une fonction récursive qui a calculé la factorielle pour toujours? P>
Le compilateur sait beaucoup sur ce que votre fonction fait. Il connaît tous les chemins de code dans la fonction. Il utilise ces connaissances sémantiques pour analyser, telles que la détection de code inaccessible, garantissant une variable est initialisée avant de lire tous les chemins de code, ...
aucun compilateur d'un langage de programmation n'a aucune idée de la sémantique du code qu'il compile. Ceci est un code valide, bien que stupide, il sera donc compilé. p>
Le compilateur comprend beaucoup sur la sémantique du code. Il serait assez facile de mettre en œuvre cet avertissement sur un niveau raisonnable. Mais je ne sais pas si cela vaut le travail pour spécifier, mettre en œuvre, documenter et maintenir cette fonctionnalité.
Comme vous avez mentionné Compiler, vérifie, vérifie des erreurs synTaticales. la fonction récursive isperfectement valide sans erreur. P>
pendant l'exécution, p>
Lorsque la pile est débordée, il jette une erreur en raison de Overflow de pile fort> * pas à cause du code em> *. P> blockQuote>
La fonction récursive est perfectionnelle valide, mais à nouveau dans la mise en œuvre, nous devons apporter la vérification des conditions de retour sur les valeurs avant que la pile ne soit remplie. P>
Voici la transaction: les avertissements du compilateur sont fonctionnalités em>. Les caractéristiques nécessitent effort em> et effort est une quantité finie. (Cela peut être mesuré en dollars ou il peut être mesuré dans le nombre d'heures que quelqu'un est disposé à donner à un projet open source, mais je vous assure, c'est fini.) P>
Par conséquent, nous devons budgétaires de cet effort. Chaque heure que nous passons de la conception, de la mise en œuvre, de la mise à l'essai et du débogage d'une fonctionnalité est une heure que nous aurions pu consacrer à faire autre chose. Par conséquent, nous sommes très prudents de décider des fonctionnalités à ajouter. P>
C'est vrai de toutes les fonctionnalités. Les avertissements ont des préoccupations supplémentaires particulières. Un avertissement doit être sur le code qui présente les caractéristiques suivantes: p>
Dans votre exemple spécifique, nous voyons que certaines de ces conditions sont remplies. Le code est légal et presque certainement faux. Mais est-ce inobvieux? Quelqu'un peut facilement regarder le code et voir qu'il s'agit d'une récursion infinie; L'avertissement n'aide pas beaucoup. Est-il possible d'analyser? L'exemple trivial que vous donnez est, mais le problème général de la recherche de récursions sans bornes équivaut à résoudre le problème d'arrêt. Est-il peu probable qu'il soit attrapé par d'autres formes de test? N ° Le moment où vous exécutez ce code dans votre cas de test, vous allez obtenir une exception pour vous dire précisément ce qui ne va pas. P>
Ainsi, cela ne vaut pas la peine de le faire pour faire cet avertissement. Il y a de meilleurs moyens que nous puissions dépenser ce budget. P>
+1 Excellente réponse et obtient vraiment ce que je demandais. Je sais que les compilateurs ne devraient pas vous empêcher d'écrire un code terrible, mais de bons compilateurs devraient au moins jeter un "hé, whatcha faire là-bas?" parfois.
Il y a le problème connexe avec int badproperty {obtenez {retournez badproperty;}} code> et son équivalent de setter, où l'erreur est très facile à faire, et non facile à repérer. Mais ce problème est clairement facile à détecter lorsque vous exécutez le code, ce qui réduit le bénéfice de cette fonctionnalité.
@Codeinchaos: En effet, c'est un endroit où l'avertissement pourrait être justifié.
Je ne suis pas d'accord avec l'inobvieux - vous devriez également obtenir des avertissements pour des erreurs évidentes.
Votre question est-elle elle-même à propos de C #, C ++ ou i> python? L'échantillon de code regarde beaucoup comme C # pour moi.
Ce n'est pas le travail du compilateur de vous empêcher de faire quelque chose de stupide. Dans la plupart des langues, il est possible que certains événements externes provoquent une construction comme celle-ci quitte.
Dans MSVC (C ++), il vous donnera un avertissement si vous appelez la fonction:
Avertissement C4717: 'Badfun': récursif sur tous les chemins de commande, la fonction entraînera un débordement de pile d'exécution code>Parce que ce n'est pas la responsabilité de l'ordinateur de vous empêcher de vous tirer intentionnellement de vous tirer dans votre propre pied: FullDupplex.org/humor/2006/10/... Voir Lisp.
Certains outils IDE vous avertiront, tels que Resharper pour C # et VB.Net dans Visual Studio.
Mais c'est le travail du compilateur de me dire que j'ai une seule variable Int inutilisée? Par opposition à quelque chose qui peut planter toute mon application si elle est appelée?
La récursion de la queue comme celle-ci peut être implémentée comme une boucle par le compilateur. Ce code peut donc ne pas être une erreur d'exécution, similaire à
tandis que (vrai); code>@ Joshin4Colours: Ce n'est pas le travail du compilateur non plus (au moins en C ++). C'est purement une qualité de la mise en œuvre de la question / équilibre le coût de la détection de ce problème (compilation des frais généraux, effort de programmation) vs les gains (attraper quelques problèmes). - Fondamentalement, il est impossible de manquer une boucle / une récursion infinie au moment de l'exécution, tandis que les variables "non utilisées" résultant de fautes de frappe peuvent conduire à des problèmes beaucoup plus subtils.
@casperone: Pourquoi cela a-t-il été fermé?
@Neilg: Juste devinez, mais au minimum, le "pourquoi" pourrait être différent pour chaque mise en œuvre (pour quatre i> langues i> Néanmoins). Question pourrie. La bonne réponse est * "Quelqu'un a décidé que les codes
d'un programmeur faisant ce travail / travail requis pour le détecter CODE> l'ont rendu trop faible une priorité pour la préoccupation. Fin de l'histoire.