Zeiger (Computerprogrammierung)
AdaEdit
Ada ist eine stark typisierte Sprache, in der alle Zeiger eingegeben werden und nur sichere Typkonvertierungen zulässig sind. Alle Zeiger werden standardmäßig auf null
initialisiert, und jeder Versuch, über einen null
-Zeiger auf Daten zuzugreifen, führt dazu, dass eine Ausnahme ausgelöst wird. Zeiger in Ada werden als Zugriffstypen bezeichnet. Ada 83 erlaubte keine Arithmetik für Zugriffstypen (obwohl viele Compiler-Anbieter dies als nicht standardmäßige Funktion vorgesehen hatten), aber Ada 95 unterstützt „sichere“ Arithmetik für Zugriffstypen über das Paket System.Storage_Elements
.
BASICEdit
Mehrere alte Versionen von BASIC für die Windows-Plattform unterstützten STRPTR (), um die Adresse eines Strings zurückzugeben, und VARPTR (), um die Adresse von zurückzugeben Eine Variable. Visual Basic 5 unterstützte auch OBJPTR (), um die Adresse einer Objektschnittstelle zurückzugeben, und einen ADDRESSOF-Operator, um die Adresse einer Funktion zurückzugeben. Die Typen all dieser sind Ganzzahlen, aber ihre Werte entsprechen Diejenigen, die von Zeigertypen gehalten werden.
Neuere Dialekte von BASIC wie FreeBASIC oder BlitzMax verfügen jedoch über umfassende Zeigerimplementierungen. In FreeBASIC wird die Arithmetik für ANY
Zeiger ( äquivalent zu C „s void*
) werden so behandelt, als ob der ANY
Zeiger eine Bytebreite wäre. ANY
Zeiger können nicht wie in C dereferenziert werden. Außerdem werden beim Umwandeln zwischen ANY
und Zeigern anderer Typen keine Warnungen generiert.
dim as integer f = 257dim as any ptr g = @fdim as integer ptr i = gassert(*i = 257)assert( (g + 4) = (@f + 1) )
C- und C ++ – Bearbeiten
In C und C ++ sind Zeiger Variablen, die Adressen und speichern kann null sein. Jeder Zeiger hat einen Typ, auf den er zeigt, aber man kann frei zwischen Zeigertypen umwandeln (aber nicht zwischen einem Funktionszeiger und einem Objektzeiger). Ein spezieller Zeigertyp, der als „ungültiger Zeiger“ bezeichnet wird, ermöglicht das Zeigen auf einen beliebigen (nicht -Funktion) Objekt, ist aber dadurch begrenzt, dass es nicht direkt dereferenziert werden kann (es soll gegossen werden). Die Adresse selbst kann häufig direkt manipuliert werden, indem ein Zeiger auf und von einem integralen Typ mit ausreichender Größe geworfen wird, obwohl die Ergebnisse implementierungsdefiniert sind und tatsächlich undefiniertes Verhalten verursachen können. Während frühere C-Standards keinen integralen Typ hatten, der garantiert groß genug war, gibt C99 den in <stdint.h>
definierten uintptr_t
typedef-Namen an. Eine Implementierung muss dies jedoch nicht bereitstellen.
C ++ unterstützt C-Zeiger und C-Typumwandlung vollständig. Es unterstützt auch eine neue Gruppe von Typecasting-Operatoren, um beim Kompilieren einige unbeabsichtigte gefährliche Casts abzufangen. Seit C ++ 11 bietet die C ++ – Standardbibliothek auch intelligente Zeiger (unique_ptr
, shared_ptr
und weak_ptr
), das in einigen Situationen als sicherere Alternative zu primitiven C-Zeigern verwendet werden kann. C ++ unterstützt auch eine andere Referenzform, die sich stark von einem Zeiger unterscheidet, der einfach als Referenz oder Referenztyp bezeichnet wird.
Zeigerarithmetik, dh die Möglichkeit, die Zieladresse eines Zeigers mit arithmetischen Operationen zu ändern (as sowie Größenvergleiche), wird durch den Sprachstandard so eingeschränkt, dass er innerhalb der Grenzen eines einzelnen Array-Objekts (oder unmittelbar danach) bleibt, und ruft ansonsten undefiniertes Verhalten hervor. Durch Hinzufügen oder Subtrahieren eines Zeigers wird es um ein Vielfaches der Größe verschoben Wenn Sie beispielsweise einem Zeiger 1 auf 4-Byte-Ganzzahlwerte hinzufügen, wird die Zeigeradresse des Zeigers um 4 erhöht. Dadurch wird der Zeiger so erhöht, dass er auf das nächste Element in einem zusammenhängenden Element zeigt Array von Ganzzahlen – was häufig das beabsichtigte Ergebnis ist. Zeigerarithmetik kann nicht für void
-Zeiger ausgeführt werden, da der void-Typ keine Größe hat und daher die angezeigte Adresse nicht hinzugefügt werden kann, obwohl gcc und andere Compiler Byte-Arithmetik für void*
als nicht standardmäßige Erweiterung, die so behandelt wird, als wäre sie char *
.
Die Zeigerarithmetik bietet dem Programmierer eine Eine Möglichkeit, mit verschiedenen Typen umzugehen: Hinzufügen und Subtrahieren der Anzahl der erforderlichen Elemente anstelle des tatsächlichen Versatzes in Bytes. (Zeigerarithmetik mit char *
Zeigern verwendet Byte-Offsets, da sizeof(char)
per Definition 1 ist.) Insbesondere erklärt die C-Definition ausdrücklich, dass die Die Syntax a
, bei der es sich um das n
-te Element des Arrays a
handelt, ist äquivalent zu *(a + n)
, dem Inhalt des Elements, auf das a + n
zeigt. Dies impliziert, dass n
a
entspricht und man beispielsweise a
schreiben kann oder 3
gleich gut, um auf das vierte Element eines Arrays a
zuzugreifen.
Zeigerarithmetik ist zwar leistungsstark, kann jedoch zu Computerfehlern führen. Es neigt dazu, unerfahrene Programmierer zu verwirren und sie in verschiedene Kontexte zu zwingen: Ein Ausdruck kann ein gewöhnlicher arithmetischer oder ein Zeigerarithmetiker sein, und manchmal ist es leicht, einen mit dem anderen zu verwechseln. Als Reaktion darauf erlauben viele moderne Computersprachen auf hoher Ebene (zum Beispiel Java) keinen direkten Zugriff auf den Speicher unter Verwendung von Adressen. Der sichere C-Dialekt Cyclone behebt auch viele Probleme mit Zeigern. Weitere Informationen finden Sie in der Programmiersprache C.
Der Zeiger void
oder void*
wird in ANSI C und unterstützt C ++ als generischer Zeigertyp. Ein Zeiger auf void
kann die Adresse eines beliebigen Objekts (keine Funktion) speichern und wird in C bei der Zuweisung implizit in einen anderen Objektzeigertyp konvertiert, muss jedoch explizit umgewandelt werden falls dereferenziert.K & RC verwendete char*
für den Zweck „typunabhängiger Zeiger“ (vor ANSI C).
C ++ erlaubt nicht die implizite Konvertierung von void*
in andere Zeigertypen, selbst bei Zuweisungen. Dies war eine Entwurfsentscheidung, um unachtsame und sogar unbeabsichtigte Casts zu vermeiden, obwohl die meisten Compiler nur Warnungen ausgeben , keine Fehler, wenn andere Casts auftreten.
In C ++ gibt es kein void&
(Verweis auf void), um void*
(Zeiger auf void), da sich Verweise wie Aliase auf die Variablen verhalten, auf die sie verweisen, und es niemals eine Variable geben kann, deren Typ void
ist.
Übersicht über die Syntax der ZeigerdeklarationEdit
Diese Zeigerdeklarationen c über die meisten Varianten von Zeigerdeklarationen. Natürlich ist es möglich, Dreifachzeiger zu haben, aber die Hauptprinzipien hinter einem Dreifachzeiger existieren bereits in einem Doppelzeiger.
The () und haben eine höhere Priorität als *.
C # Edit
In der Programmiersprache C # werden Zeiger nur unter bestimmten Bedingungen unterstützt: Jeder Codeblock einschließlich Zeigern muss mit dem Schlüsselwort unsafe
gekennzeichnet sein. Für solche Blöcke sind normalerweise höhere Sicherheitsberechtigungen erforderlich, damit sie ausgeführt werden können. Die Syntax ist im Wesentlichen dieselbe wie in C ++, und die angegebene Adresse kann entweder verwalteter oder nicht verwalteter Speicher sein. Zeiger auf den verwalteten Speicher (jeder Zeiger auf ein verwaltetes Objekt) müssen jedoch mit dem Schlüsselwort fixed
deklariert werden, wodurch verhindert wird, dass der Garbage Collector das spitze Objekt im Rahmen der Speicherverwaltung während des Der Zeiger befindet sich im Gültigkeitsbereich, sodass die Zeigeradresse gültig bleibt.
Eine Ausnahme bildet die Verwendung der Struktur IntPtr
, die ein sicher verwaltetes Äquivalent zu int*
und erfordert keinen unsicheren Code. Dieser Typ wird häufig zurückgegeben, wenn Methoden aus System.Runtime.InteropServices
verwendet werden, zum Beispiel:
Das .NET-Framework enthält viele Klassen und Methoden in System
und System.Runtime.InteropServices
Namespaces (wie die Klasse Marshal
), die .NET-Typen konvertieren (z. B. System.String
) zu und von vielen nicht verwalteten Typen und Zeigern (z. B. LPWSTR
oder void*
) Kommunikation mit nicht verwaltetem Code. Die meisten dieser Methoden haben dieselben Sicherheitsberechtigungsanforderungen wie nicht verwalteter Code, da sie sich auf beliebige Stellen im Speicher auswirken können.
COBOLEdit
Die Programmiersprache COBOL unterstützt Zeiger auf Variablen. Primitive oder Gruppen- (Datensatz-) Datenobjekte, die in LINKAGE SECTION
eines Programms deklariert sind, sind von Natur aus zeigerbasiert, wobei der einzige im Programm zugewiesene Speicher Platz für die Adresse des Datenelements ist ( typischerweise ein einzelnes Speicherwort). Im Programmquellcode werden diese Datenelemente wie jede andere WORKING-STORAGE
-Variable verwendet, aber auf ihren Inhalt wird implizit indirekt über ihre LINKAGE
-Zeiger zugegriffen
Der Speicherplatz für jedes Datenobjekt, auf das verwiesen wird, wird normalerweise dynamisch mithilfe externer CALL
-Anweisungen oder über eingebettete erweiterte Sprachkonstrukte wie oder EXEC SQL
Anweisungen.
Erweiterte Versionen von COBOL bieten auch Zeigervariablen, die mit USAGE
deklariert sind IS
POINTER
-Klauseln. Die Werte solcher Zeigervariablen werden mithilfe der Anweisungen SET
und SET
ADDRESS
festgelegt und geändert.
Einige erweiterte Versionen von COBOL bieten auch PROCEDURE-POINTER
Variablen, mit denen die Adressen von ausführbarem Code gespeichert werden können.
PL / IEdit
Die PL / I-Sprache bietet vollständige Unterstützung für Zeiger auf alle Datentypen (einschließlich Zeiger auf Strukturen), Rekursion, Multitasking, Zeichenfolgenbehandlung und umfangreiche integrierte Funktionen.PL / I war im Vergleich zu den Programmiersprachen seiner Zeit ein ziemlicher Sprung nach vorne. PL / I-Zeiger sind untypisiert, und daher ist kein Casting für die Dereferenzierung oder Zuweisung von Zeigern erforderlich. Die Deklarationssyntax für einen Zeiger lautet DECLARE xxx POINTER;
und deklariert einen Zeiger mit dem Namen „xxx“. Zeiger werden mit BASED
-Variablen verwendet. Eine basierte Variable kann mit einem Standard-Locator (DECLARE xxx BASED(ppp);
oder ohne (DECLARE xxx BASED;
) deklariert werden, wobei xxx eine basierte Variable ist eine Elementvariable, eine Struktur oder ein Array, und ppp ist der Standardzeiger. Eine solche Variable kann eine Adresse ohne explizite Zeigerreferenz (xxx=1;
) oder eine explizite Referenz auf den Standard-Locator (ppp) oder einen anderen Zeiger (qqq->xxx=1;
).
Zeigerarithmetik ist nicht Teil des PL / I-Standards, aber viele Compiler erlauben Ausdrücke der Form ptr = ptr±expression
IBM PL / I verfügt außerdem über die integrierte Funktion PTRADD
zum Ausführen der Arithmetik. Die Zeigerarithmetik wird immer in Byte ausgeführt.
IBM Enterprise PL / I-Compiler verfügen über eine neue Form eines typisierten Zeigers namens HANDLE
.
DEdit
Die Programmiersprache D ist eine Ableitung von C und C ++, die C vollständig unterstützt Zeiger und C-Typumwandlung.
EiffelEdit
Die objektorientierte Sprache von Eiffel verwendet Wert- und Referenzsemantik ohne Zeigerarithmetik. Dennoch werden Zeigerklassen bereitgestellt. Sie bieten Zeigerarithmetik, Typumwandlung und explizite Speicherverwaltung, int Erleben mit Nicht-Eiffel-Software und anderen Funktionen.
FortranEdit
Fortran-90 führte eine stark typisierte Zeigerfunktion ein. Fortran-Zeiger enthalten mehr als nur eine einfache Speicheradresse. Sie kapseln auch die unteren und oberen Grenzen von Array-Dimensionen, Schritten (zum Beispiel zur Unterstützung beliebiger Array-Abschnitte) und anderer Metadaten. Ein Zuordnungsoperator =>
wird verwendet, um eine POINTER
einer Variablen mit einer TARGET
Attribut. Die Fortran-90 ALLOCATE
-Anweisung kann auch verwendet werden, um einen Zeiger einem Speicherblock zuzuordnen. Der folgende Code kann beispielsweise zum Definieren und Erstellen einer verknüpften Listenstruktur verwendet werden:
Fortran-2003 bietet Unterstützung für Prozedurzeiger. Als Teil der C-Interoperabilitätsfunktion unterstützt Fortran-2003 intrinsische Funktionen zum Konvertieren von Zeigern im C-Stil in Fortran-Zeiger und zurück.
GoEdit
Go verfügt über Zeiger. Die Deklarationssyntax entspricht der von C, ist jedoch umgekehrt geschrieben und endet mit dem Typ. Im Gegensatz zu C verfügt Go über eine Speicherbereinigung und lässt keine Zeigerarithmetik zu. Referenztypen wie in C ++ existieren nicht. Einige integrierte Typen, wie Karten und Kanäle, sind eingerahmt (d. H. Intern sind sie Zeiger auf veränderbare Strukturen) und werden mit der Funktion make
initialisiert. Bei einem Ansatz zur einheitlichen Syntax zwischen Zeigern und Nichtzeigern wurde der Pfeiloperator (->
) entfernt: Der Punktoperator auf einem Zeiger bezieht sich auf das Feld oder die Methode des dereferenzierten Objekts . Dies funktioniert jedoch nur mit einer Indirektionsebene.
JavaEdit
Im Gegensatz zu C, C ++ oder Pascal gibt es in Java keine explizite Darstellung von Zeigern. Stattdessen werden komplexere Datenstrukturen wie Objekte und Arrays mithilfe von Referenzen implementiert. Die Sprache bietet keine expliziten Zeigermanipulationsoperatoren. Es ist jedoch weiterhin möglich, dass Code versucht, eine Nullreferenz (Nullzeiger) zu dereferenzieren, was dazu führt, dass eine Laufzeitausnahme ausgelöst wird. Der von nicht referenzierten Speicherobjekten belegte Speicherplatz wird zur Laufzeit automatisch durch Speicherbereinigung wiederhergestellt.
Modula-2Edit
Zeiger werden ebenso wie in Pascal implementiert, ebenso wie VAR
Parameter in Prozeduraufrufen. Modula-2 ist noch stärker typisiert als Pascal, mit weniger Möglichkeiten, dem Typensystem zu entkommen. Einige der Varianten von Modula-2 (wie z. B. Modula-3) umfassen die Speicherbereinigung.
OberonEdit
Ähnlich wie bei Modula-2 sind Zeiger verfügbar. Es gibt immer noch weniger Möglichkeiten, dem Typensystem auszuweichen, und so sind Oberon und seine Varianten in Bezug auf Zeiger immer noch sicherer als Modula-2 oder seine Varianten. Wie bei Modula-3 ist die Speicherbereinigung Teil der Sprachspezifikation.
PascalEdit
Im Gegensatz zu vielen Sprachen mit Zeigern können mit Standard-ISO-Pascal nur Zeiger auf dynamisch erstellte Variablen verweisen, die sind anonym und erlauben ihnen nicht, auf statische oder lokale Standardvariablen zu verweisen. Es gibt keine Zeigerarithmetik. Zeiger müssen auch einen zugeordneten Typ haben und ein Zeiger auf einen Typ ist nicht mit einem Zeiger auf einen anderen Typ kompatibel (z. B. ist ein Zeiger auf ein Zeichen nicht mit einem Zeiger auf eine Ganzzahl kompatibel).Dies hilft dabei, die Typensicherheitsprobleme zu beseitigen, die mit anderen Zeigerimplementierungen verbunden sind, insbesondere mit denen, die für PL / I oder C verwendet werden. Es beseitigt auch einige Risiken, die durch baumelnde Zeiger verursacht werden, aber die Möglichkeit, referenzierten Speicherplatz mithilfe der dispose
Standardprozedur (die den gleichen Effekt hat wie die in C gefundene free
Bibliotheksfunktion) bedeutet, dass das Risiko, dass Zeiger baumeln, nicht vollständig beseitigt wurde.
In einigen kommerziellen und Open-Source-Pascal-Compiler-Implementierungen (oder Derivaten) wie Free Pascal, Turbo Pascal oder Object Pascal in Embarcadero Delphi darf ein Zeiger jedoch auf statische oder lokale Standardvariablen verweisen und kann dies sein Umwandlung von einem Zeigertyp in einen anderen. Darüber hinaus ist die Zeigerarithmetik nicht eingeschränkt: Durch Hinzufügen oder Subtrahieren eines Zeigers wird dieser um diese Anzahl von Bytes in beide Richtungen verschoben, wobei jedoch die Inc
oder Dec
Standardprozeduren wird der Zeiger um die Größe des Datentyps verschoben, auf den deklariert werden soll. Unter dem Namen Pointer
wird auch ein untypisierter Zeiger bereitgestellt, der mit anderen Zeigertypen kompatibel ist.