Forum: Compiler & IDEs wo müssen die klammern hin. wo dürfen sie hin?


von Jop (Gast)


Lesenswert?

wenn (A+10 oder B+25) >c dann d=0

if (A+10 > c || B+25 > c) d=0;

Danke :-)

von Sven P. (Gast)


Lesenswert?

Dürfen: überall.
Müssen: Operatorenrangfolge, dazu gibts in jedem C-Buch eine Tabelle.

von Jop (Gast)


Lesenswert?

Hab gerade bei Wiki nachgeguckt.

Dann stimmt das ja so:

if (A+10 > c || B+25 > c) d=0;

Kann man sowas (unabhängig von den klammern) noch kürzen?

von U.R. Schmitt (Gast)


Lesenswert?

Jop schrieb:
> Kann man sowas (unabhängig von den klammern) noch kürzen?

Kommt immer auf den/die Term(e) an
Siehe:
http://de.wikipedia.org/wiki/Boolesche_Algebra

von U.R. Schmitt (Gast)


Lesenswert?

U.R. Schmitt schrieb:
> Siehe:
> http://de.wikipedia.org/wiki/Boolesche_Algebra

Hmm, die Seite ist wohl etwas theorielastig, aber das Thema kannst Du 
auch hier suchen. Suchwort ist Boolesche Algebra und ein Beispieltreffer 
ist
Beitrag "Freeware Boolesche Algebra Vereinfachen"

von Karl H. (kbuchegg)


Lesenswert?

Jop schrieb:
> Hab gerade bei Wiki nachgeguckt.
>
> Dann stimmt das ja so:
>
> if (A+10 > c || B+25 > c) d=0;

Ja.
Es schadet aber auch nichts, wenn man es dem Leser ein wenig einfacher 
macht und trotzdem Klammern setzt
1
    if(    ( A+10 > c )
2
        || ( B+25 > c ) )
3
      d = 0;

dann braucht man nicht lange überlegen, wie hier die 
Operatorenreihenfolge ist.
Geschrieben wird Code nur einmal, gelesen wird er aber oft. Daher ist es 
klug, sich den den Code so zu schreiben, dass man beim Lesen nicht lange 
"rätselraten" muss. Wenn man sich nicht sicher ist, dann setzt man eben 
Klammern. Das ist keine Schande. Im Zweifelsfall ist ein (unnützes) 
Klammernpaar zuviel weit weniger tragisch als ein (notwendiges) 
Klammernpaar zuwenig.

> Kann man sowas (unabhängig von den klammern) noch kürzen?

In diesem konkreten Fall: Nein.

von tuppes (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Wenn man sich nicht sicher ist, dann setzt man eben
> Klammern. Das ist keine Schande.

Im Gegenteil. Das ist keine Schande, das ist selbsterklärender Code, 
daran erkennt man den Profi.

Die Rangfolgetabelle für C hat 15 Ebenen, die für C++ sogar 18. 
Quellcode, den man nur verstehen kann, wenn man diese Tabellen auswendig 
kann, taugt nichts.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Zu viele Klammmern verringern aber auch oft die Übersichtlichkeit
(sonst hätte sich Lisp sicher besser durchesetzen können ;-)).
Deswegen sollten Klammern nicht zu üppig verwendet werden.

Dass die unären Operationen höhere Priorität haben als die binären, ist
intuitiv nachvollziehbar:
1
x = -a + b;     // gut
2
3
x = (-a) + b;   // unnötig kompliziert
4
5
x = !a && b;    // gut
6
7
x = (!a) && b;  // unnötig kompliziert

Man verdeutlich die höhere Priorität der unären Operatoren üblichweise
zusätzlich dadurch, dass diese ohne Leerzeichen vor den Operanden ge-
schrieben werden, während binäre Operatoren in zwei Leerzeichen einge-
schlossen werden (s. auch Anmerkung 1).

Ebenso ist es natürlich, dass Zuweisungsoperationen eine sehr niedrige
Priorität haben, da normalerweise erst gerechnet und erst dann das Er-
gebnis einer Variablen zugewiesen wird und nicht umgekehrt:
1
x = a + b;    // gut
2
3
x = (a + b);  // unnötig kompliziert

Niedrigere Priorität als die Zuweisungen hat nur noch der Kommaoperator,
der aber äußerst selten verwendet wird. Wer ihn überhaupt kennt, kennt
auch seine Priorität:
1
for(i=0, p=1; i<8; i++, p*=2)            // gut
2
{...}
3
4
for((i=0), (p=1); i<8; i++, (p*=2))      // unnötig kompliziert
5
{...}
6
7
for(((i=0), (p=1)); i<8; (i++, (p*=2)))  // noch unnötig komplizierter
8
{...}

Unklarheiten gibt es also höchstens zwischen den verbleibenden binären
Operationen. Diese lassen sich in C grob in drei Klassen unterteilen:

  Rechenoperationen:      Zahl op Zahl -> Zahl
  Vergleichsoperationen:  Zahl op Zahl -> Bool
  Logikoperationen:       Bool op Bool -> Bool

Man kann zwar dank der automatischen Typumwandlung in C auch mit boole-
schen Werten rechnen, boolesche Werte vergleichen oder die Ergebnisse
von Rechenoperationen logisch verknüpfen, aber das wird sehr selten
gemacht:
1
if(a > b + c) {...}            // gut
2
3
if(a > (b + c)) {...}          // unnötig kompliziert
4
5
if(a > 0 && b > 0) {...}       // gut
6
7
if((a > 0) && (b > 0)) {...}   // unnötig kompliziert

In den Beispielen wird das Weglassen der Klammern nicht zu Missverständ-
nissen führen, weil es dem gesunden Menschenverstand widerspräche, zum
Ergebnis eines Vergleichs noch einen Wert dazuzuaddieren oder das Ergeb-
nis einer logischen Und-Verknüpfung mit einem Zahlenwert zu vergleichen
(aber: s. Anmerkung 3).

Beschränkt man sich also auf die Verwendung "passender" Operandentypen
für die drei Operationsklassen, können die Operanden einer Vergleichs-
operation nur Zahlenkonstanten oder die Ergebnisse von Rechenoperationen
sein. Ebenso kommen als Operanden von Logikoperationen nur die Ergebnis-
se von Vergleichoperationen in Frage. Dadurch ist die Priorität dieser
drei Klassen untereinander auch ohne Nachschlagen im Handbuch eindeutig
festgelegt.

Meiner Meinung nach sollten Klammern deswegen nur innerhalb der drei
Klassen (insbesondere der Klasse der Rechenoperationen) gesetzt werden,
und dort auch nur dann, wenn entweder die Auswertereihenfolge geändert
werden soll (bspw. + vor *) oder wenn die Priorität ohne Nachschlagen
nicht sofort ersichtlich ist (bspw. + und <<).
1
x = a + b * c;                       // gut
2
3
x = a + (b * c);                     // unnötig kompliziert, da Punkt
4
                                     // vor Strich bereits in der Schule
5
                                     // gelehrt wird
6
7
if(a > 0 || b > 0 && c > 0) {...}    // gut
8
9
if(a > 0 || (b > 0 && c > 0))        // unnötig kompliziert, da auch die
10
{...}                                // Priorität logischer Operatoren
11
                                     // schon in der Schule gelehrt wird
12
13
if((a > 0) || ((b > 0) && (c > 0)))  // noch unnötig komplizierter
14
15
x = 1 << a + 1;                      // akzeptabel
16
17
x = 1 << (a + 1);                    // besser, da nicht jeder die Prio-
18
                                     // rität von + und auswendig kennt

Die aufgeführten Negativbeispiele sind noch relativ leicht zu lesen, da
die Ausdrücke wegen der kurzen Variablennamen mit einem Blick erfassbar
sind. Bei längeren Ausdrücken ist die Zuordnung der Klammen nicht mehr
so leicht:
1
if((coord1.x > coord2.x) || ((coord1.y > coord2.y) && (coord1.z > coord2.z)))
2
{ ...}


Anmerkung 1:

Manchmal sieht es schöner aus, die Priorität "schwieriger" Operatoron
durch geschicktes Setzen bzw. Weglassen von Leerzeichen statt durch
Klammerung hervorzuheben. Beispiel aus der AVR-Welt:
1
DDRA = 1 << PA0 | 1 << PA1 | 1 << PA2 | 1 << PA2;         // akzeptabel
2
3
DDRA = (1 << PA0) | (1 << PA1) | (1 << PA2) | (1 << PA2); // besser
4
5
DDRA = 1<<PA0 | 1<<PA1 | 1<<PA2 | 1<<PA2;                 // noch besser


Anmerkung 2:

Auch durch geignete Zeilenumbrüche kann die Operatorpriorität
verdeutlicht werden: In dem Beispiel von Kar Heinz
1
    if(    ( A+10 > c )
2
        || ( B+25 > c ) )
3
      d = 0;

sind die Teilausdrücke (also die beiden >-Vergleiche) schon so gut
voneinander abgesetzt, dass die zusätzlichen Klammern gar nicht mehr
nötig sind:
1
    if(    A+10 > c
2
        || B+25 > c )
3
      d = 0;

oder je nach Geschmack auch
1
    if(A+10 > c ||
2
       B+25 > c)
3
      d = 0;


Anmerkung 3:

Dass Rechenoperationen eine höhere Priorität als Vergleichoperationen
haben, ist zwar logisch, in C aber bei den Operatoren &, | und ^ nicht
konsequent umgegesetzt. Deswegen müssen in einigen Fällen Klammern
gesetzt werden, obwohl es dem gesunden Menschenverstand widerspricht:
1
#define DATA_MASK 0x07
2
3
if((PINA & DATA_MASK) == 5)  // richtig
4
{...}
5
6
if(PINA & DATA_MASK == 5)    // logisch, liefert aber nicht das
7
{...}                        // erwartete Ergebnis

Die C-Entwickler haben die Bitoperatoren wohl als Logikoperatoren ange-
sehen, obwohl sie in Wirklichkeit Rechenoperatoren (int op int -> int)
sind.


Damit ihr mich jetzt nicht haut: Das Vorgeschriebene ist nur meine
persönliche, subjektive Meinung ;-)

von Michael (Gast)


Lesenswert?

Alter Schwede, das war aber mal ein langer, sehr gut geschriebener Text.
Man kann bei dem, was intuitiv ist, vielleicht noch hier und da 
geteilter Meinung sein, aber im Großen und Ganzen erklärt das die 
Operator-Precedence-Regeln von C sehr gut!

von Sven P. (Gast)


Lesenswert?

Bei || und && setze ich grundsätzlich Klammern. Nicht, weil es anders 
schlechter lesbar wäre, sondern weil man durch die Klammern prima 
beschreiben kann, wie ein Ausdruck gemeint ist.

Auch wenns logisch gleichwertig ist, fallen Ausdrücke oft in eine 
Hierarchie, die 'natürlich' erscheint. Das heb ich dann gerne mit 
Klammern heraus. Wenn man das ganze Gebilde dann noch ordentlich 
einrückt, wirkt das schon übersichtlicher, als ein Haufen Ausdrücke und 
Operatoren ohne Zusammenhalt.

Aus einem Addierer:
1
  if (
2
    x > 0 && b > 0 && x > MAX - b ||
3
    x < 0 && b < 0 && x < MIN - b
4
  )
oder lieber
1
  if (
2
    ( (x > 0) && (b > 0) && (x > (MAX - b)) ) ||
3
    ( (x < 0) && (b < 0) && (x < (MIN - b)) )
4
  )
? Mir wäre letzteres deutlich lieber...

von (prx) A. K. (prx)


Lesenswert?

Wobei man sich bei fehlendem Durchblick aber drohender Klammeritis auch 
mit Leerzeichen wappnen kann: x > 0  &&  b > 0  &&  x > MAX - b

In vielen Fällen sind die Prioritäten einigermassen intuitiv, an einer 
Stelle allerdings nicht. Wenn man Bitoperation zu tun hat, dann stolpert 
man gelegentlich über den "verkehrten" Vorrang von & und ==. Hintergrund 
mag sein, dass man so auch
  x != 0  &  b != 0  &  x > MAX - b
schreiben kann, wenn abweisende Ausführung nicht erforderlich ist.

von Peter D. (peda)


Lesenswert?

Mich ärgert aber die Bevormundung durch den AVR-GCC, er meckert immer 
über fehlende Klammern bei "a & b | c".

Es ist ja recht intuitiv, daß & vorgeht. Wie bei GALs, die haben AND/OR 
Macrozellen, d.h. die AND-Verknüpfung erfolgt zuerst.

Kann man das irgendwie abschalten?


Peter

von Simon K. (simon) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:
> Mich ärgert aber die Bevormundung durch den AVR-GCC, er meckert immer
> über fehlende Klammern bei "a & b | c".
Finde ich gut.

> Es ist ja recht intuitiv, daß & vorgeht. Wie bei GALs, die haben AND/OR
> Macrozellen, d.h. die AND-Verknüpfung erfolgt zuerst.
Finde ich nicht.

Ich wüsste jetzt aus dem Stegreif nicht, warum das intuitiv sein sollte. 
Ich würde einfach 2 Klammern hinbauen, dann ist doch alles in Ordnung.

von (prx) A. K. (prx)


Lesenswert?

> Kann man das irgendwie abschalten?

Vermutlich mit -Wno-parentheses

von Klaus W. (mfgkw)


Lesenswert?

Bei GALs bestimmt nicht.


(Soviel zum Thema intuitive Zusammenfassung von Ausdrücken :-)

von Peter (Gast)


Lesenswert?

Jop schrieb:
> Hab gerade bei Wiki nachgeguckt.

Du hast nicht "bei Wiki" nachgeguckt, du has in der Wikipedia 
nachgeguckt. Wiki != Wikipedia.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.