Einfache Typen (Delphi)
Inhaltsverzeichnis |
Einfache Typen, zu denen die ordinalen und reellen Typen gehören, definieren eine Menge von Werten mit eindeutiger Reihenfolge.
Ordinale Typen
Zu den ordinalen Typen gehören Integer-, Zeichen-, boolesche, Aufzählungs- und Teilbereichstypen. Ein ordinaler Typ definiert eine Menge von Werten mit eindeutiger Reihenfolge, in der jeder Wert mit Ausnahme des ersten einen eindeutigen Vorgänger und mit Ausnahme des letzten einen eindeutigen Nachfolger hat. Die Reihenfolge der Werte wird durch deren Ordinalposition festgelegt. In den meisten Fällen hat ein Wert mit der Ordinalposition n einen Vorgänger mit der Ordinalposition n-1 und einen Nachfolger mit der Ordinalposition n+1.
Bei Integertypen ist die Ordinalposition mit dem Wert selbst identisch. Teilbereichstypen übernehmen die Ordinalposition von ihrem Basistyp. Bei allen anderen ordinalen Typen hat der erste Wert standardmäßig die Ordinalposition 0, der nächste die Ordinalposition 1 usw. In der Deklaration eines Aufzählungstyps kann diese Vorgabe überschrieben werden.
Einige vordefinierte Funktionen operieren mit ordinalen Werten und Typbezeichnern. Die wichtigsten dieser Funktionen sind in der folgenden Tabelle zusammengefasst.
| Funktion | Parameter | Rückgabewert | Bemerkungen |
|---|---|---|---|
|
Ord |
Ordinaler Ausdruck |
Ordinalposition des Ausdruckswertes |
Akzeptiert keine Int64-Argumente. |
|
Pred |
Ordinaler Ausdruck |
Vorgänger des Ausdruckswertes |
|
|
Succ |
Ordinaler Ausdruck |
Nachfolger des Ausdruckswertes |
|
|
High |
Ordinaler Typbezeichner oder Variable mit ordinalem Typ |
Höchster Wert des Typs |
Arbeitet auch mit kurzen String-Typen und Arrays. |
|
Low |
Ordinaler Typbezeichner oder Variable mit ordinalem Typ |
Niedrigster Wert des Typs |
Arbeitet auch mit kurzen String-Typen und Arrays. |
Beispielsweise liefert High(Byte) den Wert 255, weil 255 der höchste Wert des Typs Byte ist. Succ(2) liefert 3, weil 3 der Nachfolger von 2 ist.
Die Standardprozeduren Inc und Dec erhöhen bzw. verringern den Wert einer ordinalen Variable. Beispielsweise ist Inc(I) identisch mit I := Succ(I) oder mit I := I + 1, wenn I eine Integer-Variable ist.
Integertypen
Ein Integertyp repräsentiert eine Untermenge der integralen Zahlen.
Integertypen können plattformabhängig und plattformunabhängig sein.
Plattformabhängige Integertypen
Die plattformabhängigen Integertypen werden konvertiert, damit sie zu der Bitgröße der aktuellen Compiler-Plattform passen. Plattformabhängige Integertypen sind NativeInt und NativeUInt. Verwenden Sie diese Typen nach Möglichkeit, weil sie zu der besten Leistung für die zugrunde liegende CPU und das Betriebssystem führen. Die folgende Tabelle enthält die Bereiche und Speicherformate für den Delphi-Compiler.
Plattformabhängige Integertypen
| Typ | Bereich | Format | Alias |
|---|---|---|---|
|
|
32 Bit auf 32-Bit-Plattformen mit Vorzeichen oder |
||
|
|
32 Bit auf 32-Bit-Plattformen ohne Vorzeichen oder |
Plattformunabhängige Integertypen
Plattformunabhängige Integertypen haben auf jeder verwendeten Plattform immer dieselbe Größe. Zu den plattformunabhängigen Integertypen gehören ShortInt, SmallInt, LongInt, Integer, Int64, Byte, Word, LongWord, Cardinal und UInt64.
Plattformunabhängige Integertypen
| Typ | Bereich | Format | Alias |
|---|---|---|---|
-128..127
|
8 Bit mit Vorzeichen |
||
-32768..32767
|
16 Bit mit Vorzeichen | ||
-2147483648..2147483647
|
32 Bit mit Vorzeichen | ||
-2147483648..2147483647
|
32 Bit mit Vorzeichen | ||
-2^63..2^63-1
|
64 Bit mit Vorzeichen | ||
0..255
|
8 Bit ohne Vorzeichen | ||
0..65535
|
16 Bit ohne Vorzeichen | ||
0..4294967295
|
32 Bit ohne Vorzeichen | ||
0..4294967295
|
32 Bit ohne Vorzeichen | ||
0..2^64-1
|
64 Bit ohne Vorzeichen |
Generell gilt, dass arithmetische Operationen mit Integerwerten einen Wert des Typs Integer zurückliefern, der dem 32-Bit-LongInt entspricht. Operationen liefern nur dann einen Wert vom Typ Int64, wenn sie für einen oder mehrere Int64-Operanden ausgeführt werden. Deshalb ergibt der folgende Quelltext kein korrektes Resultat:
var I: Integer; J: Int64; ... I := High(Integer); J := I + 1;
Um hier einen Rückgabewert vom Typ Int64 zu erhalten, muss für I eine Typumwandlung in Int64 ausgeführt werden:
... J := Int64(I) + 1;
Weitere Informationen hierzu finden Sie unter Arithmetische Operatoren.
Hinweis: Einige Standardroutinen mit Integer-Argumenten verkürzen Int64-Werte auf 32 Bit. Die Routinen High, Low, Succ, Pred, Inc, Dec, IntToStr und IntToHex unterstützen Int64-Argumente jedoch vollständig. Auch die Funktionen Round, Trunc, StrToInt64 und StrToInt64Def geben Int64-Werte zurück. Einige wenige Routinen können keine Int64-Werte verarbeiten.
Wenn Sie den letzten Wert eines Integertyps erhöhen oder den ersten verringern, erhalten Sie als Ergebnis den niedrigsten bzw. den höchsten Wert des Bereichs. Der Typ ShortInt umfasst beispielsweise den Bereich -128..127. Deshalb hat nach Ausführung des Codes
var I: Shortint; ... I := High(Shortint); I := I + 1;
die Variable I den Wert -128. Wenn die Bereichsprüfung des Compilers aktiviert ist, führt dieser Code allerdings zu einem Laufzeitfehler.
Zeichentypen
Die Zeichentypen sind Char, AnsiChar, WideChar, UCS2Char und UCS4Char:
- Char entspricht in der aktuellen Implementierung WideChar, da der Standard-String-Typ nun UnicodeString ist. Die Implementierung des Typs Char kann sich in zukünftigen Versionen ändern. Wenn Sie Programme schreiben, in denen Zeichen unterschiedlicher Länge verarbeitet werden, sollten Sie deshalb statt hart codierter Konstanten die Standardfunktion SizeOf verwenden.
- AnsiChar-Werte stellen auf Byte-Größe (8 Bit) ausgerichtete Zeichen dar. Ihre Reihenfolge wird durch den Zeichensatz des Gebietsschemas festgelegt, wobei es sich auch um einen Multibyte-Zeichensatz handeln kann.
- WideChar-Werte stellen Zeichen mit einer Länge von mehr als einem Byte dar. In aktuellen Implementierungen repräsentieren Werte des Typs WideChar auf Word-Größe ausgerichtete (16 Bit) Zeichen. Die Größe kann sich in zukünftigen Implementierungen erhöhen. Die Reihenfolge der Zeichen ist durch den Unicode-Zeichensatz definiert. Die ersten 256 Zeichen des Unicode-Zeichensatzes entsprechen den ANSI-Zeichen.
- UCS2Char ist ein Alias für WideChar.
- UCS4Char wird für 4 Byte große Unicode-Zeichen verwendet.
Eine String-Konstante der Länge 1 (wie "A") kann einen Zeichenwert darstellen. Die vordefinierte Funktion Chr liefert den Zeichenwert aller Integerwerte im Bereich von WideChar. So gibt beispielsweise Chr(65) den Buchstaben A zurück.
Wie Integerwerte liefern auch AnsiChar- und WideChar-Werte den ersten bzw. den letzten Wert im Bereich, wenn der höchste Wert erhöht oder der niedrigste verringert wird. Beispielsweise hat nach Ausführung des Codes:
var Letter: AnsiChar; I: Integer; begin Letter := High(Letter); for I := 1 to 66 do Inc(Letter); end;
Letter den Wert A (ASCII 65).
Hinweis: Die Typen AnsiChar und WideChar werden von den mobilen Delphi-Compilern nicht unterstützt, werden aber von den Delphi-Desktop-Compilern verwendet. Weitere Informationen finden Sie unter Migrieren von Delphi-Code nach iOS vom Desktop aus.
Boolesche Typen
Es gibt 4 vordefinierte boolesche Typen: Boolean, ByteBool, WordBool und LongBool. In der Praxis wird in erster Linie der Typ Boolean verwendet. Die anderen Typen dienen der Kompatibilität zu anderen Sprachen und Betriebssystembibliotheken.
Eine Boolean-Variable belegt ebenso wie eine ByteBool-Variable ein Byte Speicherplatz. Eine WordBool-Variable belegt 2 (ein Word) und eine LongBool-Variable 4 Byte (zwei Word).
Boolesche Werte werden mit den vordefinierten Konstanten True und False dargestellt. Dabei gelten folgende Beziehungen:
| Boolean | ByteBool, WordBool, LongBool |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ein Wert vom Typ ByteBool, LongBool oder WordBool hat den Wert True, wenn seine ordinale Position ungleich Null ist. Tritt ein derartiger Wert in einem Kontext auf, in dem ein Wert vom Typ Boolean erwartet wird, wandelt der Compiler automatisch einen Wert mit einer Ordinalposition ungleich Null in den Wert True um.
Die obigen Erläuterungen beziehen sich auf die Ordinalposition von booleschen Werten, nicht jedoch auf die Werte selbst. In Delphi können boolesche Ausdrücke nicht mit Integer- oder reellen Typen verglichen werden. Wenn beispielsweise X eine Integer-Variable ist, führt die Anweisung:
if X then ...;
deshalb zu einem Compilierungsfehler. Die Umwandlung der Variable in einen booleschen Typ ist nicht empfehlenswert. Verwenden Sie stattdessen eine der folgenden Alternativen:
if X <> 0 then ...; { use an expression that returns a Boolean value }
...
var OK: Boolean; { use a Boolean variable }
...
if X <> 0 then
OK := True;
if OK then ...;
Aufzählungstypen
Aufzählungstypen definieren eine Menge von Werten mit eindeutiger Reihenfolge, indem einfach die einzelnen Bezeichner dieser Werte aneinander gereiht werden. Die Werte haben keine eigene Bedeutung. Die Syntax für die Deklaration eines Aufzählungstyps lautet:
type typeName = (val1, ...,valn)
typeName und val sind dabei gültige Bezeichner. Beispiel:
type Suit = (Club, Diamond, Heart, Spade);
Hier wird ein Aufzählungstyp mit dem Namen Suit mit den Werten Club, Diamond, Heart<code> und <code>Spade deklariert. Ord(Club) gibt in diesem Fall 0 zurück, Ord(Diamond) gibt 1 zurück usw.
Bei der Deklaration eines Aufzählungstyps wird jeder val-Wert als Konstante des Typs typeName deklariert. Wenn die val-Bezeichner innerhalb desselben Gültigkeitsbereichs auch für einen anderen Zweck eingesetzt werden, können Namenskonflikte auftreten. Angenommen, Sie deklarieren folgenden Typ:
type TSound = (Click, Clack, Clock)
Click ist gleichzeitig der Name einer Methode, die für die Klasse TControl und für alle von ihr abgeleiteten Objekte in der VCL definiert ist. Wenn Sie eine Anwendung entwickeln und die folgende Ereignisbehandlungsroutine erstellen, tritt ein Compilierungsfehler auf:
procedure TForm1.DBGridEnter(Sender: TObject);
var
Thing: TSound;
begin
...
Thing := Click;
end;
Der Compiler interpretiert Click innerhalb des Gültigkeitsbereichs der Prozedur als Referenz auf die Methode Click von TForm. Sie können dieses Problem umgehen, indem Sie den Bezeichner qualifizieren. Wenn TSound beispielsweise in MyUnit deklariert ist, lautet die korrekte Anweisung:
Thing := MyUnit.Click;
Die bessere Lösung besteht aber in der Verwendung von Konstantennamen, die nicht mit anderen Bezeichnern in Konflikt stehen. Beispiele:
type TSound = (tsClick, tsClack, tsClock); TMyColor = (mcRed, mcBlue, mcGreen, mcYellow, mcOrange); Answer = (ansYes, ansNo, ansMaybe)
Sie können die Konstruktion (val1, ..., valn) wie einen Typnamen direkt in einer Variablendeklaration angeben:
var MyCard: (Club, Diamond, Heart, Spade);
Nach dieser Deklaration von MyCard ist es aber nicht mehr möglich, im selben Gültigkeitsbereich eine weitere Variable mit diesen Konstantenbezeichnern zu deklarieren. Die Deklaration:
var Card1: (Club, Diamond, Heart, Spade); var Card2: (Club, Diamond, Heart, Spade);
führt deshalb zu einem Compilierungsfehler. Dagegen wird:
var Card1, Card2: (Club, Diamond, Heart, Spade);
ebenso wie die folgenden Anweisungen fehlerfrei compiliert:
type
Suit = (Club, Diamond, Heart, Spade);
var
Card1: Suit;
Card2: Suit;
Aufzählungstypen mit expliziter Ordinalposition
Die Zählung der Ordinalposition von Aufzählungswerten beginnt standardmäßig bei 0 und entspricht dann der Reihenfolge, in der die Bezeichner in der Typdeklaration aufgeführt sind. Sie können diese Reihenfolge überschreiben und bestimmten oder allen Werten in der Deklaration eine explizite Ordinalposition zuweisen. Geben Sie dazu nach dem Bezeichner = konstanterAusdruck ein. Dabei ist konstanterAusdruck ein konstanter Ausdruck, der zu einem Integerwert ausgewertet wird. Zum Beispiel:
type Size = (Small = 5, Medium = 10, Large = Small + Medium);
Diese Deklaration definiert einen Aufzählungstyp mit Namen Size mit den Werten Small, Medium und Large. Ord(Small) gibt in diesem Fall 5 zurück, Ord(Medium) 10 und Ord(Large) 15.
Im Grunde stellt ein Aufzählungstyp einen Teilbereich dar, dessen niedrigster und höchster Wert der niedrigsten und höchsten Ordinalposition der Konstanten in der Deklaration entsprechen. Der Typ Size im obigen Beispiel kann 11 Werte umfassen, deren Ordinalpositionen von 5 bis 15 reichen (der Typ array[Size] of Char repräsentiert also ein Array mit 11 Zeichen). Nur drei dieser Werte verfügen über einen Namen. Auf die anderen Werte kann über Typumwandlungen und Routinen wie Pred, Succ, Inc und Dec zugegriffen werden. Im folgenden Beispiel werden der Variable X anonyme Werte im Bereich von Size zugewiesen.
var X: Size; X := Small; // Ord(X) = 5 X := Size(6); // Ord(X) = 6 Inc(X); // Ord(X) = 7
Die Ordinalposition eines Wertes ohne explizite Ordinalposition ist um 1 größer als die des vorhergehenden Wertes in der Liste. Wenn dem ersten Wert keine Ordinalposition zugewiesen wird, hat er die Position 0. Daher hat bei der folgenden Deklaration:
type SomeEnum = (e1, e2, e3 = 1);
SomeEnum nur zwei mögliche Werte: Ord(e1) gibt 0 zurück, Ord(e2) 1 und Ord(e3) ebenfalls 1. Da e2 und e3 dieselbe Ordinalposition haben, stellen sie denselben Wert dar.
Aufzählungskonstanten ohne festgelegten Wert besitzen Laufzeittypinformationen:
type SomeEnum = (e1, e2, e3);
Bei Aufzählungskonstanten mit einem festen Wert ist dies nicht der Fall:
type SomeEnum = (e1 = 1, e2 = 2, e3 = 3);
Bereichsabhängige Aufzählungen
Wenn Sie die Compiler-Direktive $SCOPEDENUMS aktivieren, können Sie in Delphi-Quelltext bereichsabhängige Aufzählungen verwenden.
Bei bereichsabhängigen Aufzählungen wird einer Referenz auf ein Aufzählungstypelement der Typname vorangestellt. Der folgenden Unit können Sie entnehmen, wie eine bereichsabhängige Aufzählung (TMyEnum) die Zuweisung der Variable Value ermöglicht. Die alleinige Angabe von "First" hätte den Fehler "Nicht übereinstimmende Typen" ausgelöst:
unit Unit1;
interface
type
TMyEnum = (first, second, third);
implementation
end.
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils,
Unit1 in 'Unit1.pas';
var
First: Integer;
Value: TMyEnum;
begin
try
Value := TMyEnum.First;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
Teilbereichstypen
Ein Teilbereich ist eine Untermenge der Werte eines anderen ordinalen Typs (des sogenannten Basistyps). Alle Konstruktionen der Form Erster..Letzter, in denen Erster und Letzter konstante Ausdrücke desselben ordinalen Typs sind und Erster kleiner ist als Letzter, bezeichnen einen Teilbereichstyp, der alle Werte von Erster bis Letzter enthält. Beispielsweise können Sie für den deklarierten Aufzählungstyp:
type TColors = (Red, Blue, Green, Yellow, Orange, Purple, White, Black);
einen Teilbereichstyp der folgenden Form definieren:
type TMyColors = Green..White;
In diesem Fall umfasst TMyColors die Werte Green,Yellow, Orange, Purple und White.
Zur Definition von Teilbereichstypen können auch numerische Konstanten und Zeichen (String-Konstanten der Länge 1) verwendet werden:
type SomeNumbers = -128..127; Caps = 'A'..'Z';
Bei der Verwendung von numerischen oder Zeichenkonstanten ist der Basistyp der kleinste Integer- oder Zeichentyp, der den angegebenen Bereich enthält.
Die Konstruktion LowerBound..UpperBound funktioniert wie ein Typname, weshalb sie auch direkt in der Variablendeklaration verwendet werden kann. Zum Beispiel:
var SomeNum: 1..500;
Hier wird eine Integer-Variable deklariert, deren Wert im Bereich von 1 bis 500 liegt.
Die Ordinalposition der Werte eines Teilbereichs wird vom Basistyp bestimmt. (Wenn im ersten Beispiel Color eine Variable mit dem Wert Green ist, liefert Ord(Color) den Wert 2 zurück, unabhängig davon, ob Color den Typ TColors oder TMyColors hat.) Eine Erhöhung oder Verringerung über die Grenzen eines Teilbereichs hinaus führt nur dazu, dass der Wert in den Basistyp umgewandelt wird. Dies gilt auch dann, wenn der Basistyp ein Integer- oder Zeichentyp ist. Während die Deklaration:
type Percentile = 0..99; var I: Percentile; ... I := 100;
einen Fehler ergibt, weist die Anweisung:
... I := 99; Inc(I);
der Variable I den Wert 100 zu (sofern die Bereichsprüfung des Compilers deaktiviert ist).
Die Verwendung von konstanten Ausdrücken in Teilbereichsdefinitionen bringt ein syntaktisches Problem mit sich. Wenn in einer Typdeklaration das erste bedeutungstragende Zeichen nach einem Gleichheitszeichen (=) eine öffnende Klammer ist, geht der Compiler davon aus, dass ein Aufzählungstyp definiert wird. Somit führt der Code:
const X = 50; Y = 10; type Scale = (X - Y) * 2..(X + Y) * 2;
zu einem Fehler. Sie können dieses Problem umgehen, indem Sie bei der Typdeklaration die führende Klammer vermeiden:
type Scale = 2 * (X - Y)..(X + Y) * 2;
Reelle Typen
Ein reeller Typ definiert eine Menge von Zahlen, die in der Gleitkommanotation dargestellt werden können. Die folgende Tabelle enthält die Bereiche und Speicherformate für die reellen Typen auf 64-Bit- und 32-Bit-Plattformen.
Reelle Typen
| Typ | Positiver Näherungsbereich | Signifikante Stellen | Größe in Byte |
|---|---|---|---|
| Real48 | 2,9e-39 .. 1,7e+38
|
11-12 | 6 |
| Single | 1,5e-45 .. 3,4e+38
|
7-8 | 4 |
| Double | 5,0e-324 .. 1,7e+308
|
15-16 | 8 |
| Real | 5,0e-324 .. 1,7e+308
|
15-16 | 8 |
| Extended |
|
10-20 15-16 |
10 8 |
| Comp | -263+1 .. 263-1
|
10-20 | 8 |
| Currency | -922337203685477,5808.. 922337203685477,5807
|
10-20 | 8 |
Die folgenden Erläuterungen beziehen sich auf reellen Typen:
- Real48 wird nur aus Gründen der Abwärtskompatibilität beibehalten. Da das Speicherformat dieses Typs kein natives Format der Intel-Prozessorarchitektur ist, laufen die entsprechenden Operationen langsamer ab als mit anderen Gleitkommatypen.
- In früheren Version von Object Pascal wurde der 6 Byte große Typ Real48 Real genannt. Wenn Sie Quelltext in Delphi neu compilieren, der den älteren 6-Byte-Real-Typ enthält, sollten Sie diesen Typ in Real48 ändern. Sie können mit der Compiler-Direktive
{$REALCOMPATIBILITY ON}den Typ Real auch zurück in den 6-Byte-Typ ändern.
- Extended bietet eine höhere Genauigkeit auf 32-Bit-Plattformen als andere reelle Typen.
- Auf 64-Bit-Plattformen ist Extended ein Alias für ein Double; das heißt, dass die Größe des Datentyps Extended 8 Byte beträgt. Auf 64-Bit-Plattformen bietet Extended daher eine geringer Genauigkeit als auf 32-Bit-Plattformen, auf denen Extended 10 Byte groß ist. Wenn Sie in Ihren Anwendungen den Datentyp Extended verwenden und Genauigkeit bei Gleitkommaberechnungen wichtig ist, könnte sich dieser Größenunterschied daher auf Ihre Daten auswirken. Verwenden Sie Extended mit Bedacht, wenn Sie Datendateien anlegen, die plattformübergreifend genutzt werden sollen. Weitere Information finden Sie unter Der Datentyp "Extended" ist in 64-Bit-Windows-Systemen 2 Byte kleiner.
- Der Typ Comp (für "computational") ist ein natives Format der Intel-Prozessorarchitektur und stellt einen 64-Bit-Integer dar. Er ist dennoch als reeller Typ klassifiziert, weil sein Verhalten nicht dem eines ordinalen Typs entspricht. (Ein Comp-Wert kann beispielsweise weder inkrementiert noch dekrementiert werden.) Comp wird nur aus Gründen der Abwärtskompatibilität beibehalten. Eine höhere Ausführungsgeschwindigkeit erzielen Sie mit dem Typ Int64.
- Der Typ Currency ist ein Festkomma-Datentyp, der Rundungsfehler in finanzmathematischen Berechnungen minimiert. Er wird als skalierter 64-Bit-Integer gespeichert, bei dem die 4 niedrigstwertigen Stellen implizit vier Nachkommastellen repräsentieren. Bei einer Kombination mit anderen reellen Typen in Zuweisungen und Ausdrücken werden Currency-Werte automatisch mit 10.000 multipliziert.
Siehe auch
- Delphi-Datentypen
- Datentypen, Variablen und Konstanten
- String-Typen (Delphi)
- Strukturierte Typen
- Zeiger und Zeigertypen (Delphi)
- Prozedurale Typen
- Variante Typen
- Kompatibilität und Identität von Typen
- Typdeklaration
- Variablen
- Deklarierte Konstanten
- Interne Datenformate
- 64-Bit-Windows-Datentypen im Vergleich zu 32-Bit-Windows-Datentypen