Vor vielen Monaten musste ich einen Code reparieren, der einige Probleme verursachte. Der Code sah grundsätzlich so aus:
int badFun() { return badFun(); }
Dies verursachte offensichtlich einen Stapelüberlauf sogar in der Hochsprache, mit der ich arbeitete (4Test in SilkTest). Es gibt keine Möglichkeit, diesen Code als vorteilhaft zu betrachten. Das erste Anzeichen für Probleme waren Warnungen, die nach Abschluss des Skripts angezeigt wurden, aber keine Kompilierungsfehler oder Warnungen. Seltsamerweise habe ich versucht, Programme in C ++, C # und Python mit der gleichen Struktur zu schreiben, und alle von ihnen kompiliert / interpretiert ohne Syntaxfehler oder Warnungen, auch wenn es in allen Fällen Laufzeitfehler gab. Ich habe in keinem dieser Fälle Warnungen gesehen. Warum wird dies nicht standardmäßig als mögliches Problem angesehen?
EDIT: Ich habe versucht, das Äquivalent dieser Funktion in allen drei Sprachen zu schreiben, also habe ich diese Funktionsmarken hinzugefügt. Ich interessiere mich mehr für allgemeine Gründe, warum Code wie dieser ohne Warnungen durchkommt. Bitte bei Bedarf neu schreiben.
Hier ist der Deal: Compiler-Warnungen sind Features . Features erfordern Aufwand und Aufwand ist eine endliche Menge. (Es könnte in Dollar gemessen werden oder es könnte in der Anzahl der Stunden gemessen werden, die jemand einem Open-Source-Projekt zu geben bereit ist, aber ich versichere Ihnen, es ist endlich.)
Deshalb müssen wir diese Bemühungen einplanen. Jede Stunde, die wir damit verbringen, ein Feature zu entwerfen, zu implementieren, zu testen und zu debuggen, ist eine Stunde, in der wir etwas anderes hätten tun können. Daher sind wir sehr vorsichtig bei der Entscheidung, welche Features hinzugefügt werden sollen.
Das gilt für alle Funktionen. Warnungen haben besondere zusätzliche Bedenken. Eine Warnung muss über Code sein, der folgende Merkmale aufweist:
In Ihrem speziellen Beispiel sehen wir, dass einige dieser Bedingungen erfüllt sind. Der Code ist legal und mit ziemlicher Sicherheit falsch. Aber ist es intransparent? Jemand kann den Code leicht betrachten und erkennen, dass es sich um eine unendliche Rekursion handelt. die Warnung hilft nicht viel. Ist es einer Analyse zugänglich? Das triviale Beispiel, das Sie geben, ist, aber das allgemeine Problem, ungebundene Rekursionen zu finden, ist gleichbedeutend mit der Lösung des Halteproblems. Ist es unwahrscheinlich, dass sie von anderen Testformen erfasst werden? Nein. Sobald Sie diesen Code in Ihrem Testfall ausführen, erhalten Sie eine Exception, die Ihnen genau sagt, was falsch ist.
Es lohnt sich also nicht, diese Warnung zu machen. Es gibt bessere Möglichkeiten, wie wir dieses Budget ausgeben könnten.
Warum wird dies nicht standardmäßig als Problem angesehen?
Der Fehler ist ein Laufzeitfehler, kein Kompilierzeitfehler. Der Code ist perfekt, er macht nur etwas Dummes. Der sehr einfache Fall, den Sie zeigen, könnte sicherlich entdeckt werden, aber viele Fälle, die nur etwas komplizierter wären, wären schwer zu erkennen:
%Vor%Um festzustellen, ob das ein Problem ist, muss der Compiler versuchen herauszufinden, ob die Bedingung immer wahr ist oder nicht. Im allgemeinen Fall glaube ich nicht, dass dies berechenbarer ist, als zu bestimmen, ob das Programm irgendwann aufhört (dh es ist nachweislich nicht berechenbar <) / a>).
Kein Compiler irgendeiner Programmiersprache hat irgendeine Idee über die Semantik des kompilierten Codes. Dies ist ein gültiger Code, obwohl er dumm ist, daher wird er kompiliert.
Wie soll der Compiler oder Interpreter wissen, was die Funktion macht? Der Umfang des Compilers und Interpreters besteht darin, den syntaktischen Code zu kompilieren oder zu interpretieren - interpretiere nicht die Semantik deines Codes.
Auch wenn ein Compiler dies überprüft hat, wo zeichnest du die Linie? Was wäre, wenn Sie eine rekursive Funktion hätten, die faktoriell für immer berechnet?
Weil der Compiler nicht nach solchen Dingen sucht.
Wenn Sie einen Codeanalysator wie Resharper
in Visual Studio
installieren, wird eine Warnung über unendlichen rekursiven Aufruf oder so angezeigt, falls Sie die Codeanalyse aktiviert haben.
Ich bezweifle, dass der Compiler während der Kompilierung ein Laufzeit-Phänomen (Stack-Überlauf) erkennen kann. Es gibt viele gültige Fälle, um eine Funktion in sich selbst, Rekursion, aufzurufen. Aber wie kann der Compiler das Gute aus den schlimmen Rekursionsfällen kennen?
Wenn es nicht etwas KI hinzugefügt hat, glaube ich nicht, dass ein Compiler die Unterschiede zwischen guter und schlechter Rekursion erkennen kann, das ist die Aufgabe eines Programmierers.
Wie Sie erwähnt haben, überprüft der Compiler nur syntaktische Fehler. die rekursive Funktion ist ohne irgendeinen Fehler vollkommen gültig.
Während der Laufzeit
Wenn der Stapel überflogen wird, wird ein Fehler wegen Stapelüberlauf * ausgegeben, nicht wegen Code *.
Die rekursive Funktion ist perfekt gültig, aber in der Implementierung müssen wir die Bedingung überprüfen, um Werte zurückzugeben, bevor der Stapel gefüllt ist.
Tags und Links python c# c++ compiler-construction recursion