Warum gibt diese offensichtliche unendliche Rekursion keine Compiler-Warnung? [geschlossen]

8

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.

    
joshin4colours 06.01.2012, 17:57
quelle

7 Antworten

39

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:

  • Rechtlich. Offensichtlich muss der Code legal sein; wenn es nicht legal ist, dann ist es in erster Linie keine Warnung, es ist ein Fehler.
  • Fast sicher falsch. Eine Warnung, die Sie vor korrektem, wünschenswertem Code warnt, ist eine schlechte Warnung. (Auch wenn der Code korrekt ist, sollte es möglich sein, den Code so zu schreiben, dass die Warnung verschwindet.)
  • Unsichtbar. Warnungen sollten Sie über Fehler informieren, die eher subtil als offensichtlich sind.
  • Zugänglich für die Analyse. Manche Warnungen sind einfach unmöglich; Eine Warnung, die es erfordert, dass der Compiler das Halteproblem löst, wird nicht passieren, da dies unmöglich ist.
  • Unwahrscheinlich, von anderen Formen des Testens erfasst zu werden.

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.

    
Eric Lippert 06.01.2012, 18:39
quelle
20
  

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>).

    
Caleb 06.01.2012 18:02
quelle
3

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.

    
Mithrandir 06.01.2012 18:04
quelle
2

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?

    
Donald Miner 06.01.2012 18:03
quelle
1

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.

    
Jahan Zinedine 06.01.2012 18:01
quelle
1

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.

    
Tony The Lion 06.01.2012 18:02
quelle
0

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.

    
Manas 06.01.2012 18:08
quelle