6.2. Äquivalenz- und Vergleichsoperatoren
Die Bedingung einer if-Anweisung besteht meist aus einem Ausdruck, der einen Vergleich zwischen Variablen, Konstanten und (oder) arithmetischen Ausdrücken darstellt. Um die Gleichheit oder Ungleichheit von Operanden eines Ausdrucks bestimmen zu können, verfügt C über Äquivalenz- und Vergleichsoperatoren. Alle diese Operatoren sind binär, d.h., sie erfordern zwei Operanden.
Das Ergebnis einer Vergleichsoperation hat immer den Wert 0 oder 1, dabei steht 0 für "falsch", 1 für "wahr". Dieses Ergebnis kann bei Bedarf in arithmetischen Ausdrücken verwendet oder einer Funktion als Argument übergeben werden. Auf diese Weise läßt sich der Wahrheitswert eines Vergleichs mit printf() darstellen:
.
.
printf("Wert für wahr: %d\tWert für falsch: %d\n",
2 < 3,
7 != 7);
.
.
Äquivalenzoperatoren:
Operator | Bedeutung |
---|---|
== | gleich |
!= | ungleich |
Vergleichsoperatoren:
Operator | Bedeutung |
---|---|
<= | kleiner oder gleich |
< | kleiner |
> | größer |
>= | größer oder gleich |
Die Vergleichs- und Äquivalenzoperatoren haben, wie auch die arithmetischen Operatoren, eine Priorität und Assoziativität. Alle vier Vergleichsoperatoren genießen den gleichen Vorrang — der aber ist geringer als jener von arithmetischen Operatoren — und sind von links nach rechts assoziativ. Die beiden Äquivalenzoperatoren haben geringere Priorität als die Vergleichsoperatoren und sind ebenfalls von links nach rechts assoziativ.
Die Assoziativität der Vergleichs- und Äquivalenzoperatoren ist nur von geringem praktischen Nutzen: Die Auswertung eines Teilausdrucks ergibt immer 1 oder 0, je nachdem, ob er wahr oder falsch ist. Dieses Ergebnis wird dann mit dem nächsten Operanden verglichen. Ein Ausdruck, der mehrere Vergleichs- oder Äquivalenzoperatoren enthält, führt zu unerwarteten Ergebnissen, sofern man die in der Mathematik übliche Bewertung voraussetzt.
.
.
int iCount = 5, iBegin = 0;
unsigned short usEnd = 10;
if( iBegin < iCount < usEnd )
printf("%d",iCount);
.
.
Wer erwartet, daß die Anweisung printf("%d",iCount) ausgeführt wird, weil die Bedingung der if-Anweisung richtig ist, hat recht - wenn auch möglicherweise mit der falschen Begründung.
Der Ausdruck iBegin < iCount < usEnd ist nicht deswegen wahr, weil iCount größer als iBegin und kleiner als iEnd ist, sondern weil der dritte Operand größer als das Ergebnis des ersten Teilausdrucks ist:
Aufgrund der Links-nach-rechts-Assoziativität des Vergleichsoperators ’<’ wird zuerst iBegin < iCount ausgewertet. Das Ergebnis ist 1 (steht für "wahr"), da iBegin kleiner als iCount ist. Der nächste Vergleich lautet dann 1 < usEnd, was ebenfalls zutrifft. Damit ist der ganze Ausdruck wahr. In der Praxis ist mit derartigen Ausdrücken jedoch nichts anzufangen. Um das Anliegen, das dieser Konstruktion zugrunde liegt, formulieren zu können — nämlich festzustellen, ob iCount größer als iBegin und kleiner als iEnd ist — bedürfen wir zusätzlich logischer Operatoren (siehe dazu Kapitel 6.4.).
Das Beispielprogramm, mit dem wir unter Verwendung von getch() den Scancode von Funktionstasten abgefragt haben, läßt sich mit Hilfe einer if-Anweisung so gestalten, daß wir unterscheiden können, ob eine Sondertaste oder eine gewöhnliche Taste gedrückt wurde. Nur unter der Bedingung, daß cChar 0 ist, d.h. eine Sondertaste vorliegt, muß getch() ein zweites Mal aufgerufen werden.
/******************************************** ******
* extended.c *
* erweiterten Scancode von Sondertasten abfragen *
********************************************* *****/
#include <stdio.h> /* wg. printf() */
#include <conio.h> /* wg. getch() */
int main(void){
int iExtended;
char cChar;
printf("Bitte eine Taste drücken...\n");
cChar = getch();
/* Wert für Funktionstaste nur ermitteln,
* wenn cChar den Wert 0 hat
*/
if( cChar == 0 )
{
iExtended = getch();
printf("Sondertaste mit Scancode %d wurde"
"betätigt\n", iExtended);
}
else
printf("%c-Taste wurde betätigt", cChar );
return 0;
}
Es ist zu beachten, daß weder die if- noch die else-Anweisung mit einem Semikolon abgeschlossen wird; ein Semikolon nach if oder else hieße für den Compiler, daß der jeweilige Zweig damit beendet ist. Enthielte unser Beispielprogramm ein Semikolon nach else, dann würde der folgende printf()-Aufruf immer ausgeführt, weil er außerhalb des else-Zweiges stünde; ein Semikolon nach dem if führt allerdings zu einer Fehlermeldung, da das else nicht mehr dem if zugeordnet werden könnte. Ebensowenig kann nach der if-Anweisung auf die geschweiften Klammern verzichtet werden, da ansonsten nur die erste Anweisung nach if von der Bedingung cChar == 0 abhinge. Alle folgenden Anweisungen würden dann immer ausgeführt; zudem könnte das else dem if nicht mehr zugeordnet werden, weil dieses nicht direkt auf den if-Block folgte. Dies zöge ebenfalls eine Fehlermeldung des Compilers nach sich.