Advanced  Services Operatoren 1 Back Next Up Home


Einteilung der Operatoren

Operatoren wirken auf Literale und/oder Variablen (oder auf das Ergebnis eines Methodenaufrufes). Die Literale oder Variablen nennt man in diesem Zusammenhang auch Operanden. Ergebnis dieser Wirkung ist ein Wert. Ein einfaches und bekanntes Beispiel ist der Mutliplikationsoperator *. Er braucht zwei Operanden. So hat 17*a den Wert 34, falls die Variable a mit dem Wert 2 belegt ist. Der Mutliplikationsoperator ist ein Beispiel für einen binären Operator, er braucht zwei Operanden, um wirken zu können. Damit haben wir schon eine mögliche Einteilung der Operatoren.

Einteilung der Operatoren nach der Anzahl der Operanden Beispiel
 unäre Operatoren  Operator wirkt auf einen Operanden   -a
 binäre Operatoren  Operator wirkt auf zwei Operanden  a*b
 ternäre Operatoren   Operator wirkt auf drei Operanden   a<b ? a : b  

Mehr Möglichkeiten gibt es nicht. Ein Operator, der auf drei Operanden wirkt, ist eine Besonderheit, es gibt in C/C++, Java und C# nur einen Operator diesr Art, den Operator  ? :  für den bedingten Ausdruck.

Man kann die Operatoren auch nach der Stellung zu den Operanden ordnen. Der Mutliplikationsoperator steht zwischen den Operanden (a*b), beim Subtraktionsoperator gibt es zwei Möglichkeiten, im Falle a - b steht er zwischen den Operanden und ist binär, im Falle -a steht er vor dem Operanden und ist unär. Für manche Operatoren gibt es also mehr als eine Möglichkeit, auf einen Operanden zu wirken. Die erste Stellung nennt man infix, die zweite prefix (oder präfix). Steht der Operator nach dem Operanden, so nennt man ihn einen postfix-Operator. Der berühmteste PostfixOperator ist ++, dem die Sprache C++ ihren Namen verdankt. Von diesem Operator gibt es aber auch eine Prefixversion.

Einteilung der Operatoren nach der Stellung zu den Operanden Beispiel
 prefix-Operatoren  Operator steht vor dem Operanden  -a
 infix-Operatoren  Operator steht zwischen den Operanden   a + b
 postfix-Operatoren   Operator steht nach dem Operanden   a++  


Assoziativität

Verwendet man denselben Operator mehrmals, so muß man sich entscheiden, bei welchem Operator man mit der Auswertung des Ausdrucks anfängt. Dies ist wichtiger, als man zunächst glauben mag. Hierzu zwei Beispiele:

Falls links- und rechtsassoziative Auswertung zum gleichen Ergebnis führen, nennt man in der Mathematik einen Operator schlicht assoziativ und man kann dann Auswerten, wie man will. Ein Compiler aber hat pro Operator nur eine Möglichkeit, für ihn ist ein Operator entweder linksassoziativ oder rechtsassoziativ. Und damit stellt sich die Frage, wie der Compiler einen Ausdruck der Form a/b/c auswertet. Der Tabelle der Operatoren kann man entnehmen, daß alle arithmetischen Operatoren linksassoziativ sind. Die Klammerungen unter 1. und 3. entsprechen also der "Denkweise" unseres Compilers.

Präzedenz (Priorität, Vorrang)

Hat man zwei verschiedene Operatoren, so stellt sich nicht mehr die Frage, von links oder von rechts, sondern welcher von den beiden hat Vorrang. Die aus der Mathematik bekannte Vorrangsregel "Punkt vor Strich" gilt auch für alle Programmiersprachen. Da es aber für Programmiersprachen wesentlich mehr Operatoren gibt als die für die vier Grundrechenarten gebrächlichen Operatoren, gibt es auch sehr viel mehr Vorrangsregeln. C# kennt insgesamt nicht weniger als 13 Präzedenzstufen. Auch erfahrene Programmierer haben diese Liste nicht unbedingt im Kopf. In Zweifelsfällen behilft man sich mit einem Blick in eben diese Liste oder man setzt runde Klammern. Runde Klammern haben die höchste Präzedenz.


Arithmetische Operatoren

Die 5 arithmetische Operatoren sind in gewissem Sinn die einfachsten Operatoren in C#, weil man sie zum großen Teil noch aus der Schule kennt. Sie sind im folgenden in einem Auszug aus der Operatorentabelle zusammengefaßt. Man beachte, daß + und - sowohl unär als auch binär gebraucht werden können.

Präzedenz Operator  Bezeichnung  Assoziativität  Operandentyp 
 2 Unäre Operatoren
 +  unäres Plus  rechts  numerisch
 -  unäres minus  rechts  numerisch
 3 Multiplikation/Division
 *  Multiplikation  links  numerisch
 /  Division  links  numerisch
 %  Modulo  links  numerisch
 4 Addition/Subtraktion
 +  Addition  links  numerisch, String
 -  Subtraktion  links  numerisch

Hier einige Beispiele mit arithmetischen Operatoren

C#-Ausdruck

Auswertung durch den Compiler

1) a + 2*(b - c)/b a + ((2*(b - c))/b)
2) -b/2*a (-b/2)*a
3) -b/(2*a) -b/(2*a)
4) -b/2/a (-b/2)/a
5) - -b -(-b)
6) + +b +(+b)

Beachten sie, daß die normale Verarbeitungsrichtung des Compilers von links nach rechts ist, anders gesagt, der Compiler arbeitet linksassoziativ. Bei den Beispielen 5 und 6 dagegen arbeitet der Compiler von rechts nach links (siehe Tabelle oben) und deswegen sind solche Konstrukte legal.

Ergebnistyp

Bei der Addition von zwei int-Variablen erwartet man sozusagen autonmatisch, daß das Ergebnis vom Typ int ist. Wie sieht es aber aus, wenn man zwei int-Variablen dividiert oder wenn man eine int-Variable mit einer double-Variable multipliziert ? betrachten wir den folgenden Porgrammaussschnitt.

int a = 13 , b = 5  , c ;
double x, y ;

x = a / b ;

System.out.println("x = "+x);  // x hat den Wert 2.0

c = a * x ;   // Compiletime error : possible loss of precision

Nach der Division hat x "überraschenderweise" den Wert 2.0 und obwohl x und a einen ganzzahligen Wert haben, kann ich das Ergebnis nicht der Variablen c zuweisen. Es gibt zwei einfache Regeln, mit denen sich das Verhalten des Compilers leicht erklären läßt.

Also ergibt die Division von zwei int-Variablen wieder einen int-Wert. Nach dieser Regel ist dann etwa 26/7 gleich 3. Diesen Vorgang nennt man Ganzzahldivision, die Mathematiker schreiben dafür 26 div 7 = 3 .

Der Restoperator % (modulo)

Man kann diesen Operator als Ergänzung zur Ganzzahldivision auffassen. Während die Ganzzahldivision den ganzen Anteil liefert, liefert der Restoperator den zugehörigen Rest. In mathematischer Schreibweise:

26 div  7 = 3
26 mod 7 = 5 (Rest bei der GanzzahlDivision durch 7)

Für die erste Zeile schreiben wir   26 / 7  und für die zweite Zeile schreiben wir  26 % 7  . Der erste Ausdruck hat den Wert 3 und der zweite Ausdruck den Wert 5.

Übung

Gibt es in dem folgenden Programm eine Fehlermeldung des Compilers (compiletime error) oder gibt es einen Fehler zur Laufzeit (runtime error) oder gibt es gar keinen Fehler ?

public class Modulo2
{
   public static void Main(String[] args)
   {
      System.out.println("26%7 = " + 26%7 );
      System.out.println("7%26 = " + 7%26 );
      System.out.println("-26%7 = " + (-26%7) );
      System.out.println("26%-7 = " + 26%-7 );
      System.out.println("26.5%7.4 = " + 26.5%7.4 );
      System.out.println("0%26 = " + 0%26 );
      System.out.println("26%0 = " + 26%0 );
   }
}

Relationale Operatoren (Vergleichsopratoren)

Präzedenz  Operator  Bezeichnung  Assoziativität  Operandentyp 
 6 Relationale Operatoren 1
 <  kleiner  links  boolesch
 <=  kleiner gleich  links  boolesch
 >  größer  links  boolesch
 >=  größer gleich  links  boolesch
 7 Relationale Operatoren 2
 ==  Vergleich auf Gleichheit  links  alle
 !=  Vergleich auf Ungleichheit  links  alle

Beispiele mit relationalen Operatoren

  1. x <= 3
  2. y + 5 < 7*x
  3. x*y > 0
  4. x == y
  5. 2*x != y

Folgendes ist zu beachten: Der Operator   <=   im ersten Beispiel ist ein zusammengesetzer Operator,bestehend aus   <   und  = .  Hier müssen die beiden Zeichen ohne Abstand unmittelbar nebeneinander stehen. Ebenso besteht der Vergleichsoperator aus zwei Gleichheitszeichen ohne Abstand. Die Regel ist durchgängig. Bei allen Operatoren, die durch zwei Zeichen dargestellt werden, darf zwischen diesen Zeichen kein blank stehen.

Achtung : Konstrukte mit relationalen Operatoren ergeben immer einen booleschen Wert, also true oder false.


Boolesche Operatoren (Bitoperatoren)

Präzedenz  Operator  Bezeichnung  Assoziativität  Operandentyp 
 8 bitweise AND / vollständiges boolesches AND
 &  bitweises/boolesches AND  links  integral, boolesch
 9 bitweise XOR / boolesches XOR
 ^  bitweises/boolesches XOR  links  integral, boolesch
 10 bitweise OR / vollständiges boolesches OR
 |  bitweises/boolesches OR  links  integral, boolesch
 11 boolesches AND (shortcut-evaluation)
 &&  boolesches AND  links  boolesch
 12 boolesches OR (shortcut-evaluation)
 | |  boolesches OR  links  boolesch

Zu beiden Seiten eines booleschen Operators müssen Ausdrücke stehen, die einen booleschen Wert darstellen, deshalb werden boolesche Operatoren meist zusammen mit relationalen Operatoren verwendet. Das Ergebnis der Verknüpfung ist wieder ein boolescher Wert.

  1. 5 <= x && x < 8
  2. x > 3 || x < 0
  3. x*y > 0 && x == 0
  4. x*y > 0 || x == 0

Mit den ersten beiden Beispielen werden Bereiche auf dem Zahlenstrahl angegeben, die von einigen Zahlen erfüllt werden und von einigen nicht. Sie können also jeweils Zahlen finden, die die Bedingung erfüllen oder auch nicht. Je nachdem ergibt sich als Wert der Verknüpfung dann true oder false. Die im dritten Beispiel angegeben Bedingung ist nicht erfüllbar (warum?). Sie ergibt immer false. Die vierte Bedingung dagegen ist wieder erfüllbar (suchen Sie entsprechende Zahlen).

Bei den anderen drei Operatoren hängt die Bedeutung vom Typ des Operanden ab, sie sind also überladen. Bevorzugen Sie für die Verknüpfung von Wahrheitswerten die Operatoren mit shortcut-evaluation. Brauchen Sie ein boolesches XOR, dann müssen Sie natürlich den Operator der Stufe 9 verwenden.

Valid XHTML 1.0 Strict top Back Next Up Home