5.6 Logische Verknüpfungen
Für komplexere Bedingungen (und später auch Schleifen) können sogenannte logische Operatoren verwendet werden. Damit können Sie mehrere Ausdrücke miteinander in einer Bedingung verknüpfen. Dies ist beispielsweise nötig, wenn ein Code nur dann ausgeführt werden soll, wenn zwei oder mehrere Bedingungen oder auch nur eine von mehreren Bedingungen zutreffen. Für solche Zwecke bietet C die logischen Operatoren UND, ODER und NICHT an. Die entsprechenden Symbole sind in der folgenden Tabelle 5.2 kurz beschrieben.
Operator |
Bedeutung |
Beispiel |
Ergebnis |
---|---|---|---|
UND- Operator |
A && B |
Gibt ungleich 0 (wahr) zurück, wenn A und B ungleich 0 sind. Ansonsten wird 0 (unwahr) zurückgegeben. |
|
ODER-Operator |
A || B |
Gibt ungleich 0 (wahr) zurück, wenn A oder B (oder beide) ungleich 0 sind. Ansonsten wird 0 (unwahr) zurückgegeben. |
|
NICHT-Operator |
Gibt ungleich 0 (wahr) zurück, wenn A nicht ungleich 0 ist. Ist A hingegen ungleich 0 (wahr), wird 0 zurückgegeben. |
5.6.1 Der !-Operator
Der logische NICHT-Operator (NOT) ist ein unärer Operator und wird gerne verwendet, um eine Bedingung auf einen Fehler hin zu testen. Anstatt immer zu testen, ob eine bestimmte Bedingung gleich 0 zurückgibt, wird der !-Operator verwendet. Ein Beispiel:
if(ausdruck==0) { // Fehler }
Hier wird getestet, ob ausdruck gleich 0 ist. In der Praxis handelt es sich allerdings eher selten um eine Überprüfung, ob ein Ganzzahlwert einer Variablen gleich 0 ist, sondern ob ein bestimmter Ausdruck oder der Rückgabewert einer Funktion gleich 0 – also unwahr – und somit fehlerhaft ist. Daher finden Sie hier statt des Vergleichs mit dem ==-Operator auf 0 eher den logischen !-Operator. Die äquivalente Schreibweise mit dem logischen NICHT-Operator wäre:
if ( !ausdruck ) { // Fehler }
Hierzu ein Beispiel, das eine einfache Passworteingabe in Form einer Geheimnummer überprüft:
00 // Kapitel5/geheimnummer.c
01 #include <stdio.h>
02 int main(void) {
03 int geheimnummer = 0;
04 printf("Geheimnummer eingeben: ");
05 int check = scanf("%d", &geheimnummer);
06 if( check != 1 ) {
07 printf("Fehler bei der Eingabe\n");
08 return 1;
09 }
10 else if( ! (geheimnummer == 123456) ) {
11 printf("Geheimnummer ist falsch!\n");
12 }
13 else {
14 printf("Geheimnummer ist richtig!\n");
15 }
16 return 0;
17 }
Der logische NICHT-Operator wird in Zeile (10) ausgeführt. Es wird überprüft, ob die Bedingung zwischen den Klammern, nämlich ob die Variable geheimnummer dem Wert 123456 entspricht, nicht zutrifft. Allerdings hätten Sie in diesem Fall keinen Vorteil, wenn Sie statt der Zeile (10) folgenden äquivalenten Code verwenden würden:
if(geheimnummer != 123456 )
In der Praxis ist es tatsächlich fast immer möglich, eine Alternative für den logischen NICHT-Operator zu verwenden. Häufiger als in unserem trivialen Beispiel in geheimnummer.c wird der NICHT-Operator verwendet, um Funktionen auf eine erfolgreiche Ausführung hin zu überprüfen. Ein Beispiel wäre:
if(! funktion() ) {
// Fehler bei der Funktionsausführung
}
Logischer NICHT-Operator (seit C99)
Mit dem C99-Standard wurde als alternative Schreibweise für den logischen !-Operator das Makro not hinzugefügt, das in der Header-Datei iso646.h definiert ist. Somit würde die Schreibweise if(!a) exakt if(not a) entsprechen. Bezogen auf das Listing 5.7 würde die Zeile (10) mit dem Makro aber folgendermaßen aussehen:
#include <iso646.h> // benötigte Header-Datei für not
...
if( not (geheimnummer == 123456) ) {
// Geheimnummer falsch
}
...
5.6.2 Der &&-Operator – logisches UND
Mit dem logischen UND-Operator (&&) können Sie mehrere Operanden miteinander verknüpfen. Weil Sie zweimal & hintereinanderschreiben, weiß der Compiler, dass Sie keine Bits miteinander verknüpfen wollen. Mehrere mit UND verknüpfte Anweisungen ergeben nur dann wahr – also ungleich 0 – zurück, wenn alle einzelnen Operanden wahr sind. Ansonsten gibt der Ausdruck 0 – also unwahr – zurück. Hierzu ein Beispiel:
if( (Bedingung1) && (Bedingung2) ) {
// Beide Bedingungen sind wahr
}
else {
// Mindestens eine Bedingung ist 0 (also unwahr)
}
Das folgende Listing demonstriert den logischen UND-Operator in der Praxis:
00 // Kapitel5/und_operator.c
01 #include <stdio.h>
02 int main(void) {
03 int ival = 0;
04 printf("Eine Zahl von 1 bis 10 eingeben: ");
05 int check = scanf("%d", &ival);
06 if( check != 1 ) {
07 printf("Fehler bei der Eingabe\n");
08 return 1;
09 }
10 if( (ival > 0) && (ival <=10) ) {
11 printf("Zahl ist zwischen 1 und 10\n");
12 }
13 else {
14 printf("Zahl ist nicht zwischen 1 und 10\n");
15 }
16 return 0;
17 }
In diesem Beispiel werden Sie aufgefordert, eine Zahl zwischen 1 und 10 einzugeben. In Zeile (10) wird dann überprüft, ob der eingegebene Wert von ival größer als 0 und kleiner oder gleich 10 ist. Trifft beides zu, ist der Ausdruck wahr, und es wird die entsprechende Meldung in Zeile (11) ausgegeben. Andernfalls wird die Meldung in Zeile (14) ausgegeben.
Das Programm gibt bei der Ausführung z. B. Folgendes aus:
Eine Zahl von 1 bis 10 eingeben: 3
Zahl ist zwischen 1 und 10
Ein Zahl von 1 bis 10 eingeben: 0
Zahl ist nicht zwischen 1 und 10
Ein Zahl von 1 bis 10 eingeben: 10
Zahl ist zwischen 1 und 10
Abbruch bei einer logischen UND-Verknüpfung
Ist bei einer logischen UND-Verknüpfung die linksstehende Bedingung gleich 0 (unwahr), wird im Gegensatz zum bitweisen UND (&) die rechtsstehende Bedingung nicht mehr überprüft, weil der Gesamtausdruck bereits unwahr ist. Dieses Verhalten soll die Performance Ihres Programmes verbessern und kann bei manchen Compilern auch abgeschaltet werden.
5.6.3 Der ||-Operator – logisches ODER
Benötigen Sie hingegen eine logische Verknüpfung, bei der der gesamte Ausdruck wahr zurückgibt, wenn nur mindestens einer der verknüpften Operanden wahr ist, können Sie dies mit dem ODER-Operator (||) realisieren. Weil Sie zweimal | hintereinanderschreiben, weiß der Compiler, dass Sie keine Bits miteinander verknüpfen wollen. Auch hierzu folgt ein kurzes Beispiel, damit Sie den logischen ODER-Operator besser verstehen:
if( (Bedingung1) || (Bedingung2) ) {
// Mindestens Bedingung1 oder Bedingung2 ist wahr.
}
else {
// Beide Bedingungen sind unwahr.
}
Natürlich gibt es auch hierzu wieder ein Codebeispiel, um den ODER-Operator in der Praxis kennenzulernen:
00 // Kapitel5/oder_operator.c
01 #include <stdio.h>
02 int main(void) {
03 unsigned int uval1 = 0, uval2 = 0;
04 printf("Bitte zwei Ganzzahlen eingeben: ");
05 int check = scanf("%u %u", &uval1, &uval2);
06 if(check != 2) {
07 printf("Fehler bei der Eingabe...\n");
08 return 1;
09 }
10 if( (!uval1) || (!uval2) ) {
11 printf("Fehler: Einer der Werte ist gleich 0\n");
12 }
13 else {
14 printf("%u / %u = %lf\n",
uval1, uval2, (double)uval1/uval2);
15 }
16 return 0;
17 }
In diesem Beispiel sollen zwei Ganzzahlen uval1 und uval2 dividiert werden. Dafür werden die beiden eingegebenen Ganzzahlen in Zeile (10) mit dem logischen NICHT-Operator überprüft. Ist mindestens eine der beiden Zahlen gleich null, wird die Fehlermeldung in Zeile (11) ausgegeben und die Berechnung in Zeile (14) nicht ausgeführt.
Abbruch bei einer logischen ODER-Verknüpfung
Ist bei einer logischen Verknüpfung eine Bedingung gleich 1 (wahr), werden alle weiteren damit verknüpften Bedingungen nicht mehr überprüft, weil der Gesamtausdruck bereits wahr ist. Auch dieses Verhalten soll die Performance Ihrer Programme steigern und kann bei manchen Compilern abgeschaltet werden.
Das Programm gibt bei der Ausführung Folgendes aus:
Bitte zwei Ganzzahlen eingeben: 10 0
Fehler: Einer der Werte ist gleich 0
Bitte zwei Ganzzahlen eingeben: 10 4
10 / 4 = 2.500000
&& und || miteinander mischen
Sie können natürlich auch mit dem &&-Operator und dem ||-Operator weitere Bedingungen miteinander verknüpfen. Hierbei sollten Sie aber stets die Lesbarkeit des Codes im Auge behalten und eventuell auch Klammern setzen. Schreiben Sie also lieber if ((a==0)||(b==0)) statt if (a==0||b==0).
Logische UND- und ODER-Makros (seit C99)
Mit dem C99-Standard wurden für die logischen Operator-Gegenstücke && und || die Makros and und or eingeführt. Sie sind in der Header-Datei iso646.h definiert. Bezogen auf das Listing oder_operator.c würde somit die Zeile (10) mit den Makros wie folgt aussehen:
#include <iso646.h> // benötigte Header-Datei
...
if( (not uval1) or (not uval2) )