Einfache Typen
Nach oben zu Datentypen, Variablen und Konstanten - Index
Einfache Typen, zu denen die ordinalen und reellen Typen gehören, definieren eine Menge von Werten mit eindeutiger Reihenfolge.
Die folgenden ordinalen Typen werden in diesem Thema behandelt:
- Integer-Typen
- Zeichentypen
- Boolesche Typen
- Aufzählungstypen
- Real-Typen (Gleitkomma)
Inhaltsverzeichnis |
Ordinale Typen
Zu den ordinalen Typen gehören Integer-, Zeichen-, Aufzählungs-, Teilbereichs- und boolesche Typen. 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 Integer-Typen 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 | Anmerkungen |
|---|---|---|---|
|
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 |
Verarbeitet auch kurze String-Typen und Arrays. |
|
Low |
Ordinaler Typbezeichner oder Variable mit ordinalem Typ |
Niedrigster Wert des Typs |
Verarbeitet auch kurze 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 der ordinalen Variable. Beispielsweise ist Inc(I) identisch mit I := Succ(I) oder mit I := I + 1, wenn I eine Integer-Variable ist.
Integer-Typen
Ein Integer-Typ repräsentiert eine Untermenge der ganzen Zahlen. Es gibt zwei generische Integer-Typen: Integer und Cardinal. Diese Typen sollten, wenn möglich, immer verwendet werden, da sie die optimale Ausführungsgeschwindigkeit für die zugrunde liegende CPU und das Betriebssystem gewährleisten. Die nachfolgende Tabelle enthält die Bereiche und Speicherformate der generischen Integer-Typen für den Delphi-Compiler.
Generische Integer-Typen
| Typ | Bereich | Format |
|---|---|---|
|
Integer |
-2147483648..2147483647 |
32 Bit, mit Vorzeichen |
|
Cardinal |
0..4294967295 |
32 Bit, ohne Vorzeichen |
Fundamentale Integer-Typen
Zu den fundamentalen Integer-Typen gehören Shortint, Smallint, Longint, Int64, Byte, Word, Longword und UInt64.
Fundamentale Integer-Typen:
| Typ | Bereich | Format | Alias |
|---|---|---|---|
|
Shortint |
-128..127 |
8 Bit, mit Vorzeichen |
|
|
Smallint |
-32768..32767 |
16 Bit, mit Vorzeichen |
|
|
Longint |
-2147483648..2147483647 |
32 Bit, mit Vorzeichen |
|
|
Int64 |
-2^63..2^63-1 |
64 Bit, mit Vorzeichen |
|
|
Byte |
0..255 |
8 Bit, ohne Vorzeichen |
|
|
Word |
0..65535 |
16 Bit, ohne Vorzeichen |
|
|
Longword |
0..4294967295 |
32 Bit, ohne Vorzeichen |
|
|
UInt64 |
0..2^64-1 |
64 Bit, ohne Vorzeichen |
Generell gilt, dass arithmetische Operationen mit Integer-Werten einen Wert des Typs Integer zurückliefern, der in der aktuellen Implementierung mit dem 32-Bit-Longint identisch ist. Operationen liefern nur dann einen Wert vom Typ Int64, wenn sie für einen oder mehrere Int64-Operanden ausgeführt werden. Aus diesem Grund 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 Integer-Typs 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 eingeschaltet ist, führt dieser Code jedoch zu einem Laufzeitfehler.
Zeichentypen
Die fundamentalen Zeichentypen sind AnsiChar und WideChar. 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.
Der generische Zeichentyp ist Char. Er entspricht jetzt dem Typ WideChar, weil UnicodeString nun der Standard-String-Typ 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.
Eine String-Konstante der Länge 1 (wie "A") kann einen Zeichenwert darstellen. Die vordefinierte Funktion Chr liefert den Zeichenwert aller Integer-Werte im Bereich von AnsiChar. So gibt beispielsweise Chr(65) den Buchstaben A zurück.
Wie Integer-Werte 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).
Boolesche Typen
Es gibt vier 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 zwei (ein Word) und eine LongBool-Variable vier Byte (zwei Word).
Boolesche Werte werden mit den vordefinierten Konstanten True und False dargestellt. Dabei gelten folgende Beziehungen:
| Boolescher Wert | ByteBool, WordBool, LongBool |
|---|---|
|
False < True |
False <> True |
|
Ord(False) = 0 |
Ord(False) = 0 |
|
Ord(True) = 1 |
Ord(True) <> 0 |
|
Succ(False) = True |
Succ(False) = True |
|
Pred(True) = False |
Pred(False) = True |
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 ...; { Längeren Ausdruck verwenden, der einen booleschen Wert liefert } var OK: Boolean; ... 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:
Typ Typname = (Wert1, ...,Wertn)
Typname und Wert sind zulässige Bezeichner. Beispiel:
type Suit = (Club, Diamond, Heart, Spade);
Hier wird ein Aufzählungstyp namens Suit mit den Werten Club,Diamond, Heart und Spade deklariert. Ord(Club) gibt in diesem Fall 0 zurück, Ord(Diamond) gibt 1 zurück usw.
Jeder Wert des Aufzählungstyps wird als Konstante des Typs Typname deklariert. Wenn die Wert-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 (Wert1, ..., Wertn) 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 Anweisung
var Card1: (Club, Diamond, Heart, Spade); var Card2: (Club, Diamond, Heart, Spade);
führt deshalb zu einem Compilierungsfehler. Dagegen wird beim Ausdruck
var Card1, Card2: (Club, Diamond, Heart, Spade);
ebenso wie bei den 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 Integer-Wert ausgewertet wird. Beispiel:
type Size = (Small = 5, Medium = 10, Large = Small + Medium);
Diese Deklaration definiert einen Aufzählungstyp namens 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 Ordinalposition von 5 bis 15 reicht (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 Y := 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.
type SomeEnum = (e1, e2, e3 = 1);
SomeEnum hat 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
In Delphi-Quelltext können Sie bereichsabhängige Aufzählungen verwenden, wenn Sie die Compiler-Direktive $SCOPEDENUMS aktivieren.
Bei bereichsabhängigen Aufzählungen wird einer Referenz auf ein Aufzählungstypelement der Typname vorangestellt. In der folgenden Unit und dem dazugehörigen Programm wird gezeigt, 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 so genannten 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. Beispiel:
var SomeNum: 1..500;
Hier wird eine Integer-Variable deklariert, deren Wert im Bereich zwischen 1 und 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 vom Typ TColors oder TMyColors ist.) Dies gilt auch dann, wenn der Basistyp ein Integer- oder Zeichentyp ist. Eine Erhöhung oder Verringerung über die Grenzen eines Teilbereichs hinaus führt nur dazu, dass der Wert in den Basistyp umgewandelt wird. Während die Deklaration
type Percentile = 0..99; var I: Percentile; ... I := 100;
einen Fehler ergibt, weist die Anweisung
... I := 99; Inc(I);
der Variablen I den Wert 100 zu (sofern die Bereichsprüfung des Compilers nicht eingeschaltet 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ühren die Anweisungen
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 Gleitkommanotation dargestellt werden können. Die folgende Tabelle enthält die Bereiche und Speicherformate der fundamentalen reellen Typen in Win32.
Fundamentale reelle Typen in Win32:
| Typ | Bereich | Signifikante Stellen | Größe in Byte |
|---|---|---|---|
|
Real48 |
2,9 x 10^-39 .. 1,7 x 10^38 |
11-12 |
6 |
|
Single |
1,5 x 10^-45 .. 3,4 x 10^38 |
7-8 |
4 |
|
Double |
5,0 x 10^-324 .. 1,7 x 10^308 |
15-16 |
8 |
|
Extended |
3,6 x 10^-4951 .. 1,1 x 10^4932 |
10-20 |
10 |
|
Comp |
-2^63+1 .. 2^63-1 |
10-20 |
8 |
|
Currency |
-922337203685477.5808.. 922337203685477.5807 |
10-20 |
8 |
Der generische Typ Real entspricht in seiner aktuellen Implementierung dem Typ Double.
Generische reelle Typen:
| Typ | Bereich | Signifikante Stellen | Größe in Byte |
|---|---|---|---|
|
Real |
-5,0 x 10^-324 .. 1,7 x 10^308 |
15-16 |
8 |
Hinweis: Der Typ Real48 (6 Byte) hatte in früheren Object Pascal-Versionen den Namen Real. Wenn Sie Quelltext neu compilieren, der den alten Typ Real (6 Byte) in Delphi enthält, ändern Sie diesen Typ in Real48. Die Compiler-Direktive {$REALCOMPATIBILITY ON} wandelt den Typ Real wieder in den alten 6-Byte-Typ um.
Die folgenden Erläuterungen beziehen sich auf die fundamentalen reellen Typen:
- Real48 wird nur aus Gründen der Abwärtskompatibilität verwendet. Da das Speicherformat dieses Typs kein natives Format der Intel-Prozessorarchitektur ist, laufen die entsprechenden Operationen langsamer ab als mit anderen Gleitkommatypen.
- Extended bietet eine höhere Genauigkeit, ist aber nicht so einfach portierbar wie die anderen reellen Typen. Verwenden Sie Extended mit Bedacht, wenn Sie Datendateien anlegen, die gemeinsam und plattformübergreifend genutzt werden sollen.
- 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 ist nur aus Gründen der Abwärtskompatibilität vorhanden. Eine höhere Ausführungsgeschwindigkeit erhalten Sie mit dem Typ Int64.
- Currency ist ein Festkomma-Datentyp, der Rundungsfehler in finanzmathematischen Berechnungen minimiert. In Win32 wird er als skalierter 64-Bit-Integer gespeichert, bei dem die vier niedrigstwertigen Stellen implizit vier Nachkommastellen repräsentieren. Bei einer Kombination mit anderen reellen Typen in Zuweisungen und Ausdrücken werden Currency-Werte automatisch mit 10000 multipliziert.