Beim Lesen eines Artikels über Unterschiede in der OO- und Funktionsprogrammierung stieß ich auf Funktionszeiger. Es ist eine Weile her, seit ich mein Informatik-Studium (2003) abgeschlossen habe, und so habe ich nach Hinweisen gesucht, um mein Gedächtnis aufzufrischen.
Zeiger sind Variablen, die einen Verweis auf eine Speicheradresse enthalten. Es kann davon ausgegangen werden, dass sie auf die Daten verweisen, die in dieser Speicheradresse enthalten sind, wenn solche Daten vorhanden sind. Oder, wie im Fall des Artikels, geben sie möglicherweise den Einstiegspunkt in einen Codeabschnitt an und können zum Aufrufen dieses Codes verwendet werden.
Warum unterscheidet sich das von einer Variablen? Variablen sind symbolische Namen für Speicheradressen, und Compiler ersetzen den Namen durch die tatsächliche Adresse. Dies bedeutet, dass Variablen Verweise auf Speicherorte enthalten und als Hinweis auf die Daten an dieser Adresse betrachtet werden können, wenn solche Daten vorhanden sind.
Wenn der Unterschied im Verhalten liegt (möglicherweise kann ein Zeiger zur Laufzeit nicht neu zugewiesen werden oder kann nur ein symbolischer Variablenname zugewiesen werden, kein anderer Wert), heißt das nicht, dass es sich nur um eine Variable eines bestimmten Typs handelt, des Zeigertyps? Ebenso wird eine Variable, die als Ganzzahl deklariert ist, durch die Kompilierung dahingehend eingeschränkt, wofür sie verwendet werden kann.
Was fehlt mir hier?
quelle
Antworten:
Ihre Frage ist in mehrfacher Hinsicht interessant, da für verschiedene Themen eine sorgfältige Unterscheidung erforderlich ist. Aber Ihre Vision scheint mir im Wesentlichen richtig zu sein. Ich habe Ihre Referenz nicht gelesen, bevor ich den größten Teil dieser Antwort geschrieben habe, um meine Antwort nicht zu verzerren.
Erstens ist Ihre Aussage
Variables are symbolic names for memory addresses
fast richtig, verwirrt aber das Konzept und seine übliche Umsetzung. Eine Variable ist eigentlich nur ein Container, der einen Wert enthalten kann, der geändert werden kann. Normalerweise wird dieser Container auf einem Computer als Speicherplatz implementiert, der durch eine Adresse und eine Größe gekennzeichnet ist, da Variablen Objekte enthalten können, die Darstellungen mit mehr oder weniger Informationen erfordern.Ich werde jedoch hauptsächlich eine abstraktere Sichtweise der Semantik von Sprachen betrachten, unabhängig von Implementierungstechniken.
Variablen sind also aus abstrakter Sicht nur Container. Ein solcher Container muss keinen Namen haben. Sprachen haben jedoch häufig Variablen, die durch Zuordnen eines Bezeichners benannt werden, sodass die Verwendung der Variablen durch den Bezeichner ausgedrückt werden kann. Eine Variable kann durch verschiedene Aliasing-Mechanismen tatsächlich mehrere Bezeichner haben. Eine Variable kann auch ein Teil einer größeren Variablen sein: Ein Beispiel ist eine Zelle einer Array-Variablen, die durch Angabe der Array-Variablen und des Index der Zelle benannt werden kann, aber auch durch Aliasing mit Bezeichnern verknüpft werden kann.
Ich verwende absichtlich den Wortcontainer , der etwas neutral ist, um zu vermeiden, dass andere Wörter aufgerufen werden, die technisch semantisch geladen werden können. Es kommt dem in Wilipedia beschriebenen Referenzkonzept nahe , das häufig mit einer Speicheradresse verwechselt wird. Der Wortzeiger selbst wird oft als Speicheradresse verstanden, aber ich denke nicht, dass dies sinnvoll ist, wenn man die meisten Hochsprachen betrachtet, und wahrscheinlich unangemessen in dem Diskussionspapier, auf das Sie sich beziehen (obwohl Adressen verwendet werden können), da es unangemessen ist Verweis auf eine bestimmte Implementierung. Es ist jedoch für eine Sprache wie C geeignet, die den Implementierungskonzepten und der Maschinenarchitektur viel näher kommen soll.
Wenn Sie Variablen oder Werte auf Implementierungsebene betrachten, kann es tatsächlich mehrere komplexe Indirektionssysteme geben, von "Zeigern auf Maschinenebene", die jedoch für den Benutzer unsichtbar sind (und sein sollten), so dass die abstrakte Sichtweise Ich entwickle kann gültig sein. Bei den meisten Programmiersprachen sollte sich der Benutzer keine Gedanken über die Implementierung machen müssen oder diese überhaupt kennen, da die Implementierung für eine bestimmte Sprache sehr unterschiedlich sein kann. Dies gilt möglicherweise nicht für einige Sprachen wie C, die absichtlich nahe an der Maschinenarchitektur liegen, als fortgeschrittener Ersatz für Assemblersprachen, die in fast direktem Zusammenhang mit der expliziten Binärcodierung stehen, aber für die meisten in den meisten Fällen zu niedrig sind Situationen.
Was der Benutzer einer Sprache wissen sollte und manchmal sogar noch weniger sein sollte, sind Werte und zugehörige Operationen, wo sie enthalten sein können, wie sie Namen zugeordnet werden können, wie das Benennungssystem funktioniert, wie neue Arten von Werten definiert werden, etc.
Ein weiteres wichtiges Konzept sind Bezeichner und Namen. Die Benennung einer Entität (eines Werts) kann durch Zuordnen eines Bezeichners zu einem Wert erfolgen (normalerweise in einer Deklaration). Ein Wert kann aber auch erhalten werden, indem Operationen auf andere benannte Werte angewendet werden. Namen können wiederverwendet werden, und es gibt Regeln (Bereichsregeln), um zu bestimmen, was einem bestimmten Bezeichner je nach Verwendungskontext zugeordnet ist. Es gibt auch spezielle Namen, sogenannte Litterals, um die Werte einiger Domänen zu benennen, z. B. Ganzzahlen (z. B. ) oder Boolesche Werte (z . B. true ).612
Die Zuordnung eines unveränderlichen Werts zu einem Bezeichner wird normalerweise als Konstante bezeichnet. Litterals sind in diesem Sinne Konstanten.
"Wertecontainer" können auch als Werte betrachtet werden, und ihre Zuordnung zu einem Bezeichner ist eine Variable im üblichen "naiven" Sinne, den Sie verwendet haben. Man könnte also sagen, dass eine Variable eine "Containerkonstante" ist.
Nun fragen Sie sich vielleicht, was der Unterschied zwischen der Zuordnung eines Bezeichners zu einem Wert (Konstantendeklaration) oder der Zuweisung eines Werts zu einer Variablen ist, dh dem Speichern des Werts in dem als Containerkonstante definierten Container. Im Wesentlichen kann die Deklaration als eine Operation angesehen werden, die eine Notation definiert, die einen Bezeichner, der eine syntaktische Entität ist, einem Wert zuordnet, der eine semantische Entität ist. Die Zuweisung ist eine rein semantische Operation, die einen Status ändert, dh den Wert eines Containers ändert. In gewissem Sinne ist die Deklaration ein Metakonzept ohne semantischen Effekt, abgesehen von der Bereitstellung eines Namensmechanismus (dh eines syntaktischen Mechanismus) für semantische Entitäten.
Tatsächlich sind Zuweisungen semantische Operationen, die dynamisch auftreten, wenn das Programm ausgeführt wird, während Deklarationen syntaktischer Natur sind und normalerweise unabhängig von der Ausführung im Programmtext interpretiert werden müssen. Aus diesem Grund ist statisches Scoping (dh Text-Scoping) normalerweise der natürliche Weg, um die Bedeutung von Bezeichnern zu verstehen.
Nach all dem kann ich sagen, dass ein Zeigerwert nur ein anderer Name für einen Container ist und eine Zeigervariable eine Containervariable ist, dh ein Container (Konstante), der einen anderen Container enthalten kann (mit möglichen Einschränkungen für das enthaltene Spiel, das von einigen auferlegt wird Typ System).
In Bezug auf Code geben Sie an
[pointers] might indicate the entry point to a section of code and can be used to call that code
. Eigentlich ist das nicht ganz richtig. Ein Codeabschnitt ist oft allein bedeutungslos (aus Sicht der allgemeinen Ebene oder der Implementierung). Aus einer übergeordneten Sicht enthält Code normalerweise Bezeichner, und Sie müssen diese Bezeichner in dem statischen Kontext interpretieren, in dem sie deklariert wurden. Es gibt jedoch tatsächlich eine mögliche Duplizierung desselben statischen Kontexts, was im Wesentlichen auf eine Rekursion zurückzuführen ist, die ein dynamisches Phänomen (Laufzeitphänomen) darstellt, und der Code kann nur in einer geeigneten dynamischen Instanz des statischen Kontexts ausgeführt werden. Dies ist etwas komplex, aber die Konsequenz ist, dass das richtige Konzept das eines Abschlusses ist, der einen Code und eine Umgebung verknüpft, in der die Bezeichner interpretiert werden sollen. Der Abschluss ist das richtige semantische Konzept, dh ein richtig definierbarer semantischer Wert. Dann können Sie Abschlusskonstanten, Abschlussvariablen, habenEine Funktion ist ein Abschluss, normalerweise mit einigen Parametern, um einige ihrer Entitäten (Konstanten und Variablen) zu definieren oder zu initialisieren.
Ich überspringe viele Variationen der Verwendung dieser Mechanismen.
Verschlüsse können verwendet werden, um OO-Strukturen in imperativen oder funktionalen Sprachen zu definieren. Tatsächlich wurden frühe Arbeiten am OO-Stil (wahrscheinlich vor dem Namen) auf diese Weise durchgeführt.
Das Papier, auf das Sie verweisen und das ich schnell überflogen habe, scheint interessant zu sein und wurde von einer kompetenten Person verfasst. Es ist jedoch möglicherweise nicht einfach zu lesen, wenn Sie keine wesentlichen Erfahrungen mit einer Vielzahl von Sprachen und den zugrunde liegenden Rechenmodellen haben.
Aber denken Sie daran: Viele Dinge sind in den Augen des Betrachters, solange er eine einheitliche Sichtweise bewahrt. Die Standpunkte können abweichen.
Beantwortet das deine Frage?
PS: Das ist eine lange Antwort. Wenn Sie einen Teil davon für unzureichend halten, geben Sie bitte ausdrücklich an, um welchen es sich handelt. Danke.
quelle
Der Unterschied besteht per Definition und Anwendung darin, dass ein Zeiger eine spezialisierte Variable ist, die eine Speicheradresse einer anderen Variablen enthält. In OO-Begriffen würde ein Zeiger möglicherweise sein Verhalten von einer allgemeinen Klasse namens Variable erben.
quelle