Programmierkurs: Delphi: Pascal: Operatoren

Aus Wikibooks

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