Programmierkurs: Delphi: Pascal: Operatoren
Wie kann man nun mit den vorhandenen Werten, Variablen und Konstanten arbeiten, also zum Beispiel rechnen, Werte übertragen oder vergleichen? Dazu benötigt man Operatoren. Einige davon haben Sie in den vorherigen Beispielen bereits kennen gelernt.
In diesem Kapitel erfahren Sie, welche Operatoren existieren und für welche Zwecke Sie diese verwenden können.
Verwendete Begriffe
[Bearbeiten]Im Zusammenhang mit Operatoren werden bestimmte Begriffe verwendet. Rätselraten ist nicht jedermanns Sache, deswegen wollen wir diese vorher klären.
Zum einen unterscheiden sich die Operatoren in binäre und unäre. Binär (aus dem lateinischen bini, „je zwei“ bzw. bina, „paarweise“) werden solche Operatoren genannt, die jeweils zwei Operanden benötigen, also z.B. X + Y oder 3 * a. Daneben gibt es noch die unären Operatoren (lat. unus „ein, einer“), welche nur einen Operanden haben. Hiermit sind die Vorzeichen + und - gemeint, die in Delphi ebenfalls direkt vor einer Zahl oder einer Variablen stehen, z.B. -21
, +15.9
oder -X
. Weitere unäre Operatoren sind der Wahrheits- und logische Operator not
, der Adressoperator @
, sowie der Zeigeroperator ^
, der ausnahmsweise hinter dem Operanden steht.
Allgemeine Operatoren
[Bearbeiten]Zuweisungsoperator :=
[Bearbeiten]Wie in den vorangegangen Beispielen schon kurz beschrieben, ist der Operator :=
für Zuweisungen von Werten an Variablen bestimmt. Hierbei steht auf der linken Seite die Variable, die einen Wert erhalten soll (hier sind nur Variablen, Klasseneigenschaften, sowie - mit entsprechender Kompilierung (siehe vorheriges Kapitel) - zuweisbare typisierte Konstanten erlaubt). Auf der rechten Seite können z.B. feste Werte stehen, Konstanten, andere Variablen, Klasseneigenschaften, Funktionsaufrufe und so weiter. Der Datentyp auf der rechten Seite muss dabei kompatibel zum Datentyp der Variablen auf der linken Seite sein.
const
Konstante = 255;
var
Fliesskomma: Double;
Ganzzahl: Integer;
Text: string;
Zeichen: Char;
begin
Fliesskomma := 6.5; // erlaubt
Fliesskomma := 20; // erlaubt
Ganzzahl := 5; // erlaubt
Ganzzahl := 17.385; // nicht erlaubt, da nicht kompatibel
Ganzzahl := Konstante; // erlaubt
Text := 'Hallo';
Zeichen := 'Z'; // erlaubt, da nur 1 Zeichen
Zeichen := 'Hallo'; // nicht erlaubt, da mehrere Zeichen = Zeichenkette
end.
Adressoperator @
[Bearbeiten]Mit dem Adressoperator @
lässt sich die Speicheradresse jeder Variablen, Routine oder Klassenmethode ermitteln. Nicht erlaubt sind Typen, Konstanten, Interfaces und konstante Werte. Der Adressoperator gibt einen generischen Zeiger (Typ Pointer) auf die jeweilige Speicheradresse zurück.
Arithmetische Operatoren
[Bearbeiten]Die arithmetischen Operatoren verwenden Sie für Berechnungen. Wie im „echten Leben“ gilt auch hier die Regel: Punktrechnung geht vor Strichrechnung. Wenn Sie also keine Klammern setzen, wird immer zuerst multipliziert und geteilt, bevor Addition und Subtraktion erfolgen. In Delphi gibt es außerdem noch weitere Operatoren, daher erfahren Sie am Ende dieses Kapitels, in welcher Rangfolge diese zueinander stehen.
Folgende arithmetische Operatoren gibt es:
Operator | Funktion | Ergebnistyp |
---|---|---|
+ | Addition | Ganzzahl, Fließkommazahl |
- | Subtraktion | Ganzzahl, Fließkommazahl |
* | Multiplikation | Ganzzahl, Fließkommazahl |
/ | Gleitkommadivision | Fließkommazahl |
div | Ganzzahldivision | Ganzzahl |
mod | Divisionsrest | Ganzzahl |
Der Ergebnistyp richtet sich nach den Datentypen der Operanden. Ist mindestens einer davon ein Fließkommatyp, so trifft dies auch auf das Ergebnis zu. Nur, wenn ausschließlich ganzahlige Typen verwendet werden, ist auch das Ergebnis ganzzahlig. Bei der Gleitkommadivision mittels /
erhalten Sie, wie der Name schon sagt, immer eine Gleitkommazahl als Ergebnis. Bei div
und mod
erhalten Sie hingegen immer eine Ganzzahl, daher wird bei div
das Ergebnis immer auf die nächste Ganzzahl abgerundet.
Wahrheitsoperatoren
[Bearbeiten]Die Wahrheitsoperatoren werden nach dem englischen Mathematiker George Boole auch Boolesche Operatoren genannt. Diese verknüpfen verschiedene Wahrheitswerte miteinander und geben als Ergebnis wieder einen Wahrheitswert zurück. Als Operanden sind daher nur solche Ausdrücke erlaubt, die sich sozusagen mit „wahr“ oder „falsch“, bzw. „ja“ oder „nein“ beantworten lassen. Es sind auch Vergleiche als Operanden möglich, diese müssen dann in Klammern gesetzt werden.
Operator | Funktion | Beispiel |
---|---|---|
not | Verneinung | not (X > Y)
|
and | Und-Verknüpfung | DateiGefunden and (Eintraege > 2)
|
or | Oder-Verknüpfung | (PLZ in [20001..22769]) or (Ort = 'Hamburg')
|
xor | exklusive Oder-Verknüpfung | rechts xor links
|
- Die Verneinung
not
kehrt den Wert des Operanden um. - Die Und-Verknüpfung
and
ergibt nur dann „wahr“, wenn beide Operanden wahr sind. - Die Oder-Verknüpfung
or
ergibt „wahr“, wenn mindestens 1 Operand wahr ist. - Die exklusive Oder-Verknüpfung
xor
ergibt hingegen nur „wahr“, wenn genau 1 Operand wahr ist.
Eine Und-Verknüpfung ergibt immer „falsch“, sobald ein Operand falsch ist. Aus diesem Grund bietet Delphi die Möglichkeit, alle weiteren Prüfungen abzubrechen, wenn bereits der erste Operand „falsch“ ist. Diese vollständige Auswertung kann mit {$B-}
deaktiviert werden, was bei Delphi bereits voreingestellt ist.
Logische Operatoren
[Bearbeiten]Die logischen Operatoren verwendet man zum bitweisen Auswerten und Ändern von Ganzzahlen. Sie verhalten sich so ähnlich wie die Wahrheitsoperatoren. Bei den Wahrheitsoperatoren wird immer nur 1 Bit bearbeitet und dieses als „wahr“ oder „falsch“ interpretiert. Die logischen Operatoren hingegen verwenden mehrere Bits gleichzeitig, das Ergebnis ist dann jeweils wieder eine neue Zahl.
Operator | Funktion | Beispiel |
---|---|---|
not | bitweise Negation | not X
|
and | bitweise Und-Verknüpfung | Y and 32
|
or | bitweise Oder-Verknüpfung | X or Y
|
xor | bitweise exklusive Oder-Verknüpfung | Z xor B
|
shl | bitweise Verschiebung nach links | C shl 4
|
shr | bitweise Verschiebung nach rechts | T shr 2
|
Exkurs: binäres Zahlensystem
Um mit der bitweisen Verschiebung zu arbeiten, muss man sich im binären Zahlensystem auskennen. Jede Zahl setzt sich dabei aus den einzelnen Zahlwerten 20, 21, 22,...2n zusammen. Die 2 bedeutet hierbei, dass es nur zwei Möglichkeiten gibt, also 0 oder 1. „n“ ist das für den Zahltyp höchstmögliche Bit. Das kleinste Bit steht dabei ganz rechts, das höchste links.
Ein kurzer Überblick, bezogen auf ein Byte:
Bit-Nr. | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Wert (2Bit) | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
Beispiel für 17 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 |
Die 17 hat damit den Binärcode 00010001 und errechnet sich aus 1*24 + 1*20. 17 shl 2
ergibt somit 01000100 = 1*26 + 1*22 = 64 + 4 = 68.
Merke: Es gibt nur 10
Typen von Menschen - solche, die Binärcode lesen können, und solche, die es nicht können!
Vergleichsoperatoren
[Bearbeiten]Wie der Name schon sagt, dienen diese Operatoren dazu, zwei Werte miteinander zu vergleichen. Die Datentypen auf beiden Seiten des Operators müssen zueinander kompatibel sein. Als Ergebnis erhält man immer einen Wahrheitswert, also true oder false.
Operator | Funktion | Beispiel |
---|---|---|
= | gleich | X = 17
|
<> | ungleich | Text <> "Hallo"
|
< | kleiner als | Laenge < Max
|
> | größer als | Einkommen > 999.99
|
<= | kleiner als oder gleich | Index <= X
|
>= | größer als oder gleich | Alter >= 18
|
Zeichenkettenoperatoren
[Bearbeiten]Bis auf die Vergleichsoperatoren gibt es für Zeichenketten nur den Operator +
, mit dem man zwei Zeichenketten oder eine Zeichenkette mit einem einzelnen Zeichen verketten kann.
Beispiele:
'Hallo' + ' Welt'
ergibt'Hallo Welt'
'Hallo Welt' + Chr(33)
ergibt'Hallo Welt!'
Mengenoperatoren
[Bearbeiten]Mengen können ebenfalls auf einfache Weise bearbeitet werden. Hierfür stehen folgende Operatoren zur Verfügung:
Operator | Funktion | Ergebnistyp | Beispiel | Ergebnis |
---|---|---|---|---|
+ | Vereinigung | Menge | Menge + [1, 3, 5] | alle Elemente von Menge, zusätzlich 1, 3 und 5 |
- | Differenz | Menge | Menge1 - Menge2 | alle Elemente von Menge1 ohne die von Menge2 |
* | Schnittmenge | Menge | Menge1 * Menge2 | alle Elemente, die sowohl in Menge1, als auch in Menge2 enthalten sind |
<= | Untermenge | Wahrheitswert | [7, 8] <= Menge | true, wenn 7 und 8 in Menge enthalten sind |
>= | Obermenge | Wahrheitswert | Menge1 >= Menge2 | true, wenn Menge2 vollständig in Menge1 enthalten ist |
= | gleich | Wahrheitswert | Menge = [2, 4, 6] | true, wenn Menge nur aus den Zahlen 2, 4 und 6 besteht |
<> | ungleich | Wahrheitswert | Tage <> [1, 8, 15, 22, 29] | true, wenn Tage nicht aus den Elementen 1, 8, 15, 22 und 29 besteht |
in | Element von | Wahrheitswert | X in Menge | true, wenn der Wert X in Menge enthalten ist |
Hinweis: Bei in
muss der erste Operand ein Einzelwert vom Typ der Elemente der geprüften Menge sein. Alle anderen Operatoren erfordern Mengen auf beiden Seiten.
Zeigeroperatoren
[Bearbeiten]Für die Arbeit mit Zeigern sind die folgenden Operatoren bestimmt:
Operator | Funktion | Ergebnistyp | Beispiel |
---|---|---|---|
+ | Addition | Zeiger auf ein Zeichen | P + X |
- | Subtraktion | Zeiger auf ein Zeichen oder Ganzzahl | P - X |
^ | Dereferenz | Basistyp des Zeigers | PFachnummer^ |
= | gleich | Wahrheitswert | Pointer1 = Pointer2 |
<> | ungleich | Wahrheitswert | Pointer1 <> Pointer2 |
Bei der Addition und Subtraktion können immer nur Zeiger auf Zeichen verwendet werden, also PChar, PAnsiChar und PWideChar. Es kann immer nur eine Ganzzahl zu einem solchen Zeiger addiert werden, was bedeutet, dass die Adresse um diese Anzahl Zeichen nach hinten verschoben wird. Die Subtraktion funktioniert hierbei genauso, verschiebt den Zeiger jedoch nach vorne. Man kann auch zwei Zeichenzeiger voneinander subtrahieren. In diesem Falle erhält man eine Ganzzahl, die die Differenz zwischen beiden Zeigeradressen angibt (den so genannten Offset).
Die Dereferenz ist bei allen typisierten Zeigern möglich, man erhält damit den Zugriff auf die Daten, die an dieser Speicheradresse liegen. Da beim generischen Typ Pointer die Art der Daten an dessen Speicheradresse nicht bekannt ist, kann bei Variablen dieses Typs keine direkte Dereferenzierung verwendet werden. Man muss zuerst eine Typumwandlung auf die auszulesenden oder zu ändernden Daten durchführen.
Der Vergleich zweier Zeiger mittels =
und <>
erfolgt nur in Bezug auf die Speicheradresse, auf die diese zeigen, nicht auf den Inhalt der Daten an diesen Adressen. Also nur, wenn bei beiden Zeigern die Speicheradresse identisch ist, gibt der Operator =
den Wert true zurück. Ein kleines Beispiel:
var
p1, p2: ^Integer;
p3: Pointer;
begin
New(p1); // Speicher für den 1. Zeiger reservieren
New(p2); // Speicher für den 2. Zeiger reservieren
p1^ := 200; // an beiden Speicheradressen werden dieselben Daten abgelegt
p2^ := 200; // oder: p2^ := p1^
Writeln(p1 = p2); // Ausgabe: FALSE
Writeln(p1 <> p2); // Ausgabe: TRUE
Dispose(p2); // Speicher des 2. Zeigers freigeben
p2 := p1; // Adresse des 2. Zeigers auf die des 1. setzen
Writeln(p1 = p2); // Ausgabe: TRUE
Writeln(p1 <> p2); // Ausgabe: FALSE
Dispose(p1);
{ Arbeit mit untypisierten Zeigern }
GetMem(p3, 1); // Speicher für den 3. Zeiger reservieren, Größe muss der Verwendung entsprechen
Byte(p3^) := 42; // eine Zahl eintragen
Writeln(Byte(p3^)); // gibt 42 aus
Char(p3^) := 'o'; // jetzt ein Zeichen zuweisen
Writeln(Char(p3^)); // gibt o aus
Writeln(Byte(p3^)); // erlaubt! Gibt Dezimalwert von o, also 111 aus
FreeMem(p3); // Speicher für den 3. Zeiger freigeben
end.
Klassenoperatoren
[Bearbeiten]Um mit Klassen zu arbeiten, können folgende Operatoren verwendet werden:
Operator | Funktion | Ergebnistyp | Beispiel |
---|---|---|---|
= | gleich | Wahrheitswert | Instanz1 = Instanz2 |
<> | ungleich | Wahrheitswert | Var1 <> Var2 |
is | Klassentyp prüfen | Wahrheitswert | Instanz is TKlasse |
as | Klassentyp interpretieren | Klasseninstanz | Instanz as TKlasse |
Bei den Vergleichen mittels =
und <>
müssen zwei Klasseninstanzen als Operanden angegeben werden. Da es sich bei Klasseninstanzen intern um Zeiger handelt, funktionieren diese beiden Operatoren genau wie oben bei den Zeigeroperatoren beschrieben.
Mit dem Operator is
kann geprüft werden, ob eine Klasseninstanz von einem bestimmten Klassentyp bzw. von diesem abgeleitet ist. Links steht dabei die Klasseninstanz, rechts der zu prüfende Klassentyp.
Mittels as
lässt sich eine Klasseninstanz wie ein anderer Klassentyp interpretieren. Der Klassentyp auf der rechten Seite muss dabei ein Nachfahre der Instanz auf der linken Seite sein und die Instanz muss als dieser Typ erstellt worden sein. Daher muss vorher mittels is
geprüft werden, ob die Instanz auch den benötigten Typ hat.
Da sich alle Klassen von TObject ableiten, kann man hiermit generisch verschiedene Klassen in seiner Anwendung „herumreichen“. Je nachdem, welcher Typ dann tatsächlich vorliegt, können die entsprechenden Methoden aufgerufen werden. Das Thema Klassenoperationen wird ausführlich in einem späteren Kapitel behandelt.
Rangfolge der Operatoren
[Bearbeiten]Die verschiedenen Operatoren werden in einer bestimmten Reihenfolge ausgeführt. Wenn man nichts anderes benötigt, gilt auch in Delphi der Satz „Punktrechnung vor Strichrechnung“. Hier ist eine kleine Übersicht, in welcher Rangfolge alle Operatoren zueinander stehen.
Rang | Operatoren |
---|---|
1. | @, not |
2. | *, /, div, mod, and, shl, shr, as |
3. | +, -, or, xor |
4. | =, <, >, <>, <=, >=, in, is |
Die höherwertigsten Operationen werden immer zuerst ausgeführt, gleichrangige von links nach rechts. Um die Reihenfolge zu ändern, muss man die gewünschten vorrangigen Operationen in Klammern setzen (z.B. 1 + 2 * 3
ergibt 7, (1 + 2) * 3
hingegen 9).
Pascal: Variablen und Konstanten | Inhaltsverzeichnis | Pascal: Input und Output |