Warum ist es unmöglich zu bauen, einen compiler, der bestimmen kann, ob eine C++ - Funktion, ändert sich der Wert einer bestimmten Variablen?
Lese ich diese Zeile in einem Buch:
Es ist nachweislich unmöglich, zu bauen, einen compiler, der kann eigentlich
bestimmen, ob oder ob nicht eine C++ - Funktion, ändert sich der Wert eines
bestimmte variable.
Wurde der Absatz darum, warum der compiler ist konservativ, wenn die Prüfung für const-ness.
Warum ist es unmöglich, den Bau eines solchen compiler?
Kann der compiler überprüfen Sie immer, ob eine variable zugewiesen wird, eine nicht-const-Funktion aufgerufen wird, oder wenn es weitergegeben wird in eine nicht-const-parameter...
- Erste Sache, die kommt meiner Meinung dynamic link libraries. Wenn ich kompilieren von code auf meinem Rechner, und kompilieren Sie code auf Ihrem Rechner, und wir verknüpfen zur Laufzeit, wie könnte dein compiler wissen, ob ich die modifizierten Variablen oder nicht?
- Wenn ich bitten Sie für die Eingabe in mein Programm und basiert auf, dass ich entweder ändern oder nicht ändern, eine bestimmte variable. Dann kann nie vorausgesagt werden zur compile-Zeit, ob ich den Wert der variable nicht. Es könnte, aber Sie kann nicht sicher sagen, es "wird".
- Genau dieses. Mehr breit, die der compiler nicht kompilieren der Funktion einzeln, aber kompiliert es als Teil eines umfassenderen Bildes, die möglicherweise nicht alle innerhalb der compiler-Bereich.
- aber ich bin nicht immer, warum jemand wollen, um zu wissen, dass die Funktion ändern sich einige Werte während der Ausführung,da gibt es einige andere Möglichkeiten, um die Spur der Zustand der Variablen oder den Wert.
- MooingDuck Hat code-Objekt markieren, wenn eine bestimmte Funktion ist const? Auch in Ihrem header-Datei, wenn Sie markiert eine oder mehrere Ihrer Funktionen als const oder einen der Parameter const, der compiler kann dann bestimmen, wenn der code ändert Variablen oder nicht. Richtig? Wenn ja, dann auch wenn Sie kompiliert deinen code an Ihre Maschine, und Sie gab mir Ihre Kopf, mein compiler kann ermitteln, ob die variable geändert wird oder nicht. Richtig?
- "unmöglich" ist vielleicht eine übertreibung - "rechnerisch unmöglich" (wie im NP-hart) eine bessere Charakterisierung, ist aber ein wenig schwieriger für die Schüler zu fassen. Stellen Sie sich eine Link-Liste oder andere abstrakte Datenstruktur. Wenn ich eine Funktion aufzurufen, die änderungen, die man Knoten in der Liste/Baum/was auch immer, wie kann ein compiler jemals hoffen, um zu beweisen genau, welche Knoten geändert habe (und was vielleicht noch wichtiger ist, welche nicht), ohne im wesentlichen vollständig zu simulieren, das Programm mit den erwarteten Eingang, alle zwar nicht unter 3 Tagen zu kompilieren eine source-Datei...
- Unmöglich ist keine übertreibung, das Halteproblem gilt hier mehrere Antworten erklären. Es ist einfach nicht möglich, algorithmisch vollständig analysieren zu einem Allgemeinen Programm.
- Wie vereinbart, für die ganz Allgemeine/willkürliche Fall. Jedoch, viele gut ausgebaute Programme ordnungsgemäße überprüfung der Eingabe nicht zu tun haben mit "beliebige Eingabe", und so kann nicht von Instanzen der vollständige Halteproblem, aber einige reduzierte Teilmenge, die möglicherweise sehr gut nachweisbar, wenn auch nicht unbedingt effizient...
- Compiler, die nur kompilieren eine Teilmenge der gültigen Programme sind nicht sehr nützlich.
- Ich Stimme zu, es ist definitiv eine subsprache, wo das Halteproblem nicht gelten. Aber von Turing ' s Beweis wir können folgern, dass solche subsprache ist nicht mehr turing-vollständig, also wirklich nicht so interessant.
- Wenn der Compiler könnte diese Art von Analyse darüber, wie sich ein Programm verhält, würden wir nicht brauchen, um ausführen unserer Programme. (Ich bin mir sicher, dass ist ein grober overgeneralization.)
- Ich denke, das ist eine Variante der so genannten "Halteproblem". Gegeben ein beliebiges Programm in einem genügend reiche Programmier-Sprache ist es unmöglich zu bestimmen, ob die Kontrolle überhaupt fließt durch einen bestimmten Punkt. Beachten Sie, dass dies nicht einfach "schwierig", es ist wirklich unmöglich.
- Sie scheinen zu vergessen, dass dies keine reinen Mathe-problem - "Das problem ist, zu bestimmen, da ein Programm und einen input an das Programm, ob das Programm irgendwann stoppen, wenn mit diesem Eingang." Wenn einer sagt: "Während die Entscheidung, ob diese Programme (wie "Hallo Welt") die Einstellung ist einfach, komplexere Programme als problematisch erweisen." - dies bedeutet, dass Sie gehen in das Gebiet der mathematischen Logik.
- Während eine "richtige" compiler sollte in der Lage sein zu kompilieren jede gültige Programm, die Teilmenge der gültigen Programme, die wirklich nützlich sind, ist sehr klein (aber immer noch unendlich, und keine mögliche Art und Weise zu charakterisieren, den Satz), so ist auch eine "gebrochene" compiler beherrscht nur "nützliche" Programme (was auch immer das bedeutet) ist noch... die Meisten Compiler bemühen, "richtig" ist, aber aufgrund von bugs und anderen Unzulänglichkeiten nie ganz komplett, dieses Ziel zu erreichen...
void UserChange() { int* p; scanf("%p", &p); (*p)++; }
unmöglich zu sagen, was hier geändert werden zur Laufzeit.- Das Buch ist text, ist unklar, welche verschleiert das Problem. Es ist der Versuch zu sagen, "Holen wir uns eine unendliche Anzahl von Affen, die schreiben jeden erdenklichen C++ - Funktion, die jemals geschrieben werden. Es wird Fälle geben, wo, wenn wir wählen eine variable, die (einige bestimmte Funktion, die Affen geschrieben) verwendet, können wir nicht herausfinden, ob die Funktion ändern, die variable." Natürlich für einige (sogar viele) Funktionen in einer bestimmten Anwendung, diese kann bestimmt werden, indem der compiler, und sehr leicht. Aber nicht für alle (oder unbedingt die meisten).
- Aus demselben Grund kann man nicht erkennen, Endlosschleife, (können Sie feststellen, es gibt eine Pause-Taste auf der Tastatur, die Sie drücken müssen, selbst wenn man glaubt, dass Sie Ihren code in Endlosschleife)
- Kann jemand erklären warum der Letzte Satz meiner Frage falsch ist? Warum ist diese Prüfung nicht genug? Hier ist die Letzte Frage: Der compiler kann immer überprüfen, ob seine zugewiesen wird, eine nicht-const-Funktion aufgerufen wird, oder wenn es weitergegeben wird in eine nicht-const-parameter. Warum ist diese Prüfung nicht ausreichend, um zu bestimmen, const-ness?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Aus dem gleichen Grund kann man nicht ein Programm schreiben, dass wird bestimmen, ob ein bestimmtes Programm beendet wird. Dies ist bekannt als die Halteproblem, und es ist eines jener Dinge, die nicht berechenbar sind.
Klar zu sein, Sie können schreiben Sie einen compiler, der bestimmen kann, dass eine Funktion ändert die variable in einigen Fällen, aber Sie können nicht schreiben, eine, die zuverlässig sagt Ihnen, dass das funktionieren wird oder nicht, ändern Sie die variable (oder halt), für alle möglichen Funktionen.
Hier ist ein einfaches Beispiel:
Wie kann ein compiler bestimmen, nur aus der Betrachtung, dass der code, ob
foo
jemals ändern wirda
? Ob es tut oder nicht, hängt von den Bedingungen der externen auf die Funktion, nämlich die Umsetzung derbar
. Es ist mehr als das, um den Beweis, dass das Halteproblem nicht berechenbar ist, aber es ist schon schön erklärt in dem verlinkten Wikipedia-Artikel (und in jedem Berechnungs-Theorie-lehrbuch), also werde ich nicht versuchen zu erklären, es richtig hier.foo(int x) { if (x < 1) a = 3;
Vorstellen, wie compiler existiert. Lassen Sie uns auch davon ausgehen, dass für die Bequemlichkeit es bietet eine Bibliothek-Funktion, die 1 zurückgibt, wenn die übergebene Funktion ändert eine gegebene variable ist und 0, wenn die Funktion nicht. Was soll dann mit diesem Programm drucken?
modifies_variable()
viel mehr wissen, als es tatsächlich ist...f
ändert sich die variable nicht, ob Sie es ändern könnte, die variable. Diese Antwort ist richtig.f
hier, nachdem alle. Und Nein, man kann nicht einfach so beheben, dass durch das Verbot der indirekten Aufrufe so gut.modifies_variable(f, variable)
ist wahr, aber ich hielt die "API -" so einfach wie möglich für Klarheit. Ihr zweiter Punkt, den ich nicht akzeptiere. Beachten Sie, dass das Buch sagte, es ist nachweislich unmöglich. Für mich ist es klar, dass das Buch versucht zu vermitteln, den mathematischen Aspekt und der Bezug zum Halteproblem/ähnliche Probleme. Und während Sie mit einem nicht-statisch auswertbaren Faktor - wie ein geiger-Zähler angeschlossen an den PC - das wäre eine einfachere und leichter verständliche Aspekt des Problems nicht in der grundsätzlichen Unmöglichkeit dieses problem.modifies_variable
aus dem compiler-source, völlig zunichte Ihrem argument. (vorausgesetzt, open-source, aber der Punkt sollte klar sein)Nicht zu verwechseln "werden oder nicht, ändern einer variable gegeben, diese Eingänge" für "hat einen Ausführungspfad, ändert eine variable."
Ersteres nennt Opak-Prädikat-Bestimmung, und ist trivial unmöglich zu entscheiden - abgesehen von der Reduktion vom Halteproblem, Sie konnte nur darauf aus, die Eingänge stammen möglicherweise aus einer unbekannten Quelle (zB. die Benutzer). Dies gilt für alle Sprachen, nicht nur C++.
Letztere Aussage, jedoch kann bestimmt werden, indem man den parse-Baum, die ist etwas, das alle optimizing Compiler tun. Der Grund, warum Sie tun, ist, dass Reine Funktionen (und referentiell transparent Funktionen, für einige definition referentiell transparent) haben alle möglichen schönen Optimierungen angewendet werden können, wie leicht inlinable oder mit Ihren ermittelten Werte zur compile-Zeit, aber zu wissen, ob eine Funktion rein, die wir brauchen, um zu wissen, ob es kann jemals ändern einer variable.
So, was zu sein scheint eine überraschende Aussage über C++ ist eigentlich eine triviale Aussage über alle Sprachen.
Glaube ich das Stichwort in "ob oder ob nicht eine C++ - Funktion, ändert sich der Wert einer bestimmten variable" ist "wird". Es ist sicherlich möglich, erstellen Sie einen compiler, der prüft, ob oder ob nicht eine C++ - Funktion darf ändern Sie den Wert einer bestimmten variable, Sie kann nicht mit Sicherheit sagen, dass die Veränderung geschehen wird:
const
-ness überprüft.if (reply == "Y") {
stattif (reply == Y) {
...Ich glaube nicht, dass es notwendig ist, rufen Sie das Halteproblem zu erklären, dass Sie nicht algorithmisch wissen zur compile-Zeit, ob eine gegebene Funktion zu ändern, eine bestimmte variable oder nicht.
Stattdessen ist es ausreichend zu zeigen, dass eine Funktion das Verhalten hängt oft von Laufzeit-Bedingungen, die der compiler kann nicht wissen, über Sie im Voraus. E. g.
Wie könnte man den compiler mit Sicherheit voraussagen, ob
y
geändert werden?Es getan werden kann und Compiler sind tun es die ganze Zeit für einige Funktionen, das ist zum Beispiel eine triviale Optimierung für einfache inline-Accessoren oder viele Reine Funktionen.
, Was unmöglich ist zu wissen, dass es im Allgemeinen Fall.
Immer, wenn es ein system Anruf oder einen Aufruf der Funktion aus einem anderen Modul, oder ein Anruf zu einem potenziell überschreiben-Methode, alles, was passieren könnte, enthalten die feindliche übernahme von einigen hacker verwenden eines stack-überlauf zu ändern, dass eine unabhängige variable.
Allerdings sollten Sie verwenden, const, vermeiden globals, lieber Referenzen auf Zeiger, vermeiden, wiederverwenden Variablen voneinander unabhängigen Aufgaben, etc. das macht der compiler das Leben leichter, wenn die Durchführung aggressive Optimierungen.
Gibt es mehrere Möglichkeiten, zu erklären, diese, von denen die Halteproblem:
Wenn ich ein Programm schreiben, das wie folgt aussieht:
Nicht den Wert von
x
ändern? Um dies zu ermitteln, Sie müsste zunächst, um zu bestimmen, ob diedo tons of complex stuff
Teil bewirkt, dass die Bedingung zur Feuer - oder sogar mehr-basic, ob es hält. Das ist etwas, was der compiler kann das nicht tun.Wirklich überrascht, dass es nicht eine Antwort, die über das Halteproblem direkt! Es ist eine sehr einfache Reduktion von dieses problem das Halteproblem.
Vorstellen, dass der compiler könnte erkennen, ob oder nicht eine Funktion verändert den Wert einer Variablen. Dann wäre es sicherlich in der Lage sein zu sagen, ob die folgende Funktion ändert den Wert von y oder nicht, vorausgesetzt, dass der Wert von x sein kann, verfolgt alle Anrufe in den rest des Programms:
Nun für jedes Programm, die wir mögen, wir umschreiben es so:
Beachten Sie, dass, wenn, und nur wenn unser Programm ändert sich der Wert von y ist, tut es dann beenden - von foo() ist das Letzte, was er tut, vor dem beenden. Dies bedeutet, dass wir gelöst haben das Halteproblem!
Was die obige Reduktion zeigt uns, dass das problem der Bestimmung, ob eine variable den Wert ändert, ist mindestens so hart wie das Halteproblem. Das Halteproblem ist bekannt, incomputable, also das muss man auch sein.
y
. Sieht für mich wiefoo()
gibt schnell, und dannmain()
beendet. (Sie können auch anrufenfoo()
ohne ein argument... das ist ein Teil meiner Verwirrung.)Sobald eine Funktion ruft eine andere Funktion, die der compiler nicht "sehen", die Quelle, die es entweder davon ausgehen muss, dass die variable verändert wird, oder die Sachen können auch schief gehen, weiter unten. Zum Beispiel, sagen wir, wir haben diese in "foo.cpp":
und wir haben diese in "bar.cpp":
Wie kann der compiler "weiß", dass
x
ist nicht zu ändern (oder ändern, in geeigneter Weise) inbar
?Ich bin sicher, wir können kommen mit etwas komplexer, wenn das noch nicht Komplex genug.
const_cast
foo, wäre es immer noch machenx
ändern - ich würde in Verletzung des Vertrages, die besagt, dass Sie nicht zu ändernconst
Variablen, aber da kann man konvertieren, alles zu "mehr const", undconst_cast
vorhanden ist, der Designer der Sprache sicherlich hatte die Idee im Hinterkopf, dass es manchmal gute Gründe zu glauben, dassconst
Werte können geändert werden.Ist es unmöglich, im Allgemeinen für den compiler, um festzustellen, ob die variable wird geändert werden, wie schon betont wurde.
Beim Check-const-ness, die Frage von Interesse zu sein scheint, wenn die variable kann geändert werden, indem eine Funktion. Auch dies ist schwer in Sprachen, die Unterstützung von Zeigern. Sie können nicht kontrollieren, was andere code wird mit einem Zeiger, es könnte sogar sein, Lesen aus einer externen Quelle (obwohl unwahrscheinlich). In Sprachen, die den Zugang zu Speicher, sind diese Arten von Garantien möglich sein kann, und mehr aggressive Optimierung als C++ tut.
Um die Frage spezifischer, schlage ich die folgende Reihe von Einschränkungen können zu dem geworden, was der Autor des Buches mag im Sinn gehabt haben:
Im Kontext der compiler-design, ich denke Annahmen 1,3,4 durchaus Sinn machen, in der Ansicht von einem compiler Schriftsteller im Kontext der code-gen Richtigkeit und/oder code-Optimierung. Annahme 2 macht Sinn in der Abwesenheit des volatile-Schlüsselwort. Und diese Annahmen konzentrieren sich auch die Frage genug, um die Beurteilung einer vorgeschlagenen Antwort viel mehr endgültiger 🙂
Gegeben diese Annahmen, ist ein wesentlicher Grund, warum const-ness nicht angenommen werden kann, ist aufgrund der variable aliasing. Der compiler kann nicht wissen, ob eine andere variable Punkte in der const variable. Aliasing könnte durch eine andere Funktion in der selben compilation unit, in dem Fall der compiler könnte auch der Blick über die Funktionen und Nutzung einer call-Baum statisch zu bestimmen, die aliasing auftreten könnten. Aber wenn das aliasing ist durch eine Bibliothek oder andere ausländische code und der compiler hat keine Möglichkeit zu wissen, die auf Funktion Eintrag, ob Variablen Aliasing.
Könnte man argumentieren, dass wenn eine variable/argument ist const markiert dann sollte es nicht geändert werden, die über aliasing, aber für einen compiler schreibt, der ist ziemlich riskant. Es kann sogar riskant sein, für einen menschlichen Programmierer, um eine variable zu deklarieren const als Teil von, sagen wir, ein großes Projekt, wo er nicht weiß, wie das Verhalten des ganzen Systems, oder das OS, oder eine Bibliothek, um wirklich zu wissen, eine variable nicht zu ändern.
Selbst wenn eine variable deklariert wird
const
sind, bedeutet nicht, schlecht geschriebenen code kann überschrieben werden.Ausgabe:
a
undb
sind stack-Variablen, undb[1]
nur zufällig die gleiche Speicherposition wiea
.const
wenn alles gekennzeichnet istconst
. Es ist, weil Undefiniertes Verhalten ist ein Teil von C/C++. Ich war auf der Suche nach einer anderen Antwort auf seine Frage anstatt zu erwähnen das Halteproblem oder externe menschlichen input.Erweitern auf meine Kommentare, das Buch ist text, ist unklar, welche verschleiert das Problem.
Als ich kommentierte, dass das Buch versucht zu sagen, "Holen wir uns eine unendliche Anzahl von Affen, die schreiben jeden erdenklichen C++ - Funktion, die jemals geschrieben werden. Es wird Fälle geben, wo, wenn wir wählen eine variable, die (einige bestimmte Funktion, die Affen geschrieben) verwendet, können wir nicht herausfinden, ob die Funktion ändern, die variable."
Natürlich für einige (sogar viele) Funktionen in einer bestimmten Anwendung, diese kann bestimmt werden, indem der compiler, und sehr leicht. Aber nicht für alle (oder unbedingt die meisten).
Diese Funktion kann so leicht analysiert:
"foo" klar, ändert sich nicht "global". Es nicht ändern, überhaupt nichts, und ein compiler kann diese Arbeit sehr leicht.
Dieser Funktion können Sie nicht so analysiert:
Da "foo"'s Aktionen hängt davon ab einen Wert ändern können zur Laufzeit, es offensichtlich nicht bestimmt werden kann zur compile-Zeit ob es sich ändern wird "global".
Dieses ganze Konzept ist weit einfacher zu verstehen als Informatiker machen es aus zu sein. Wenn die Funktion etwas anderes machen, basierend auf Dinge, die sich zur Laufzeit ändern kann, dann kann man nicht herausfinden, was es tun werde, bis es läuft, und jedes mal, wenn es läuft, kann es etwas anders machen. Ob es nachweislich unmöglich oder nicht, es ist offensichtlich unmöglich.