Geschichte der Frage
Die Priorität von Operatoren wurde in C eingeführt, um die Reihenfolge der Berechnungen in mathematischen und logischen Ausdrücken zu steuern. Obwohl mathematische Operatoren historisch betrachtet eine erwartete Priorität haben (wie in der Algebra), hat das Auftreten vieler neuer Operatoren (logisch, bitweise, Zuweisung usw.) das Bild komplizierter gemacht. Um die Wahrscheinlichkeit von Fehlern zu verringern und die Lesbarkeit zu erhöhen, wurde eine offizielle Liste der Prioritäten und Assoziativität von Operatoren geschaffen.
Problem
Durch die Vielzahl von Operatoren und deren unterschiedlichen Natur (arithmetisch, Vergleich, Zuweisung, logisch, Indizierung) treten Mehrdeutigkeiten bei der Erstellung komplexer Ausdrücke auf. Ein falsches Verständnis der Reihenfolge ihrer Anwendung führt zu logischen Fehlern und nicht immer offensichtlichen Bugs, insbesondere bei der Kombination von bitweisen und logischen Operatoren, Zeigern, Inkrementen und dem ternären Operator.
Lösung
Beispielcode:
#include <stdio.h> int main() { int a = 1, b = 2, c = 3, d; d = a + b * c; // b*c wird zuerst ausgeführt: d = 1 + (2*3) = 7 printf("%d\n", d); d = a + b << 1; // a + b = 3, dann 3 << 1 (6) printf("%d\n", d); d = a < b ? a++ : b++; printf("%d\n", d); // a < b ist wahr => d = a (1), a wird nachher erhöht }
Wichtige Merkmale:
Was gibt der Ausdruck x = y > z ? y : z; zurück, wenn man die Klammern vergisst?
Antwort: Der ternäre Operator ?: hat eine niedrigere Priorität als >. Zuerst wird (y > z) berechnet und dann wird zwischen y und z gewählt. Aber wenn man dies mit einer Zuweisung kombiniert, können unerwartete Effekte auftreten. Es ist besser, immer Klammern zu verwenden: x = (y > z) ? y : z;.
*Was gibt der Ausdruck p++ und warum zurück?
Antwort: Der Postinkrementoperator (++) hat eine höhere Priorität als die Dereferenzierung (*), daher wird *p++ zu *(p++): zuerst wird p verwendet und erhöht, erst dann wird dereferenziert, was sich von *++p (Dereferenzierung nach Inkrement) unterscheidet.
Warum funktioniert der Ausdruck a & b == c nicht wie erwartet?
Antwort: Der Operator == hat eine höhere Priorität als &, daher wird der Ausdruck als a & (b == c) analysiert, und nicht als (a & b) == c, was zu unerwarteten Ergebnissen führen kann. Für die gewünschte Logik müssen Klammern verwendet werden.
if ((a & b) == c) { ... }
Negativer Fall
Bei der Optimierung von Code hat ein Programmierer mehrere Operatoren ohne Klammern kombiniert: if( mask & flag == 0 ) ..., was dazu führte, dass die Logik der Überprüfung falsch war und zu einem Systemfehler führte.
Vorteile:
Nachteile:
Positiver Fall
Verwendung von expliziter Gruppierung: if( (mask & flag) == 0 ) ..., die Logik ist klar, Flags sind leicht zu ändern.
Vorteile:
Nachteile: