mikrocontroller.net

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


Autor: Jop (Gast)
Datum:

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

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

Danke :-)

Autor: Sven P. (haku) Benutzerseite
Datum:

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

Autor: Jop (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: U.R. Schmitt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: U.R. Schmitt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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"

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
    if(    ( A+10 > c )
        || ( B+25 > c ) )
      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.

Autor: tuppes (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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:
x = -a + b;     // gut

x = (-a) + b;   // unnötig kompliziert

x = !a && b;    // gut

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:
x = a + b;    // gut

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:
for(i=0, p=1; i<8; i++, p*=2)            // gut
{...}

for((i=0), (p=1); i<8; i++, (p*=2))      // unnötig kompliziert
{...}

for(((i=0), (p=1)); i<8; (i++, (p*=2)))  // noch unnötig komplizierter
{...}

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:
if(a > b + c) {...}            // gut

if(a > (b + c)) {...}          // unnötig kompliziert

if(a > 0 && b > 0) {...}       // gut

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 <<).
x = a + b * c;                       // gut

x = a + (b * c);                     // unnötig kompliziert, da Punkt
                                     // vor Strich bereits in der Schule
                                     // gelehrt wird

if(a > 0 || b > 0 && c > 0) {...}    // gut

if(a > 0 || (b > 0 && c > 0))        // unnötig kompliziert, da auch die
{...}                                // Priorität logischer Operatoren
                                     // schon in der Schule gelehrt wird

if((a > 0) || ((b > 0) && (c > 0)))  // noch unnötig komplizierter

x = 1 << a + 1;                      // akzeptabel

x = 1 << (a + 1);                    // besser, da nicht jeder die Prio-
                                     // 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:
if((coord1.x > coord2.x) || ((coord1.y > coord2.y) && (coord1.z > coord2.z)))
{ ...}


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:
DDRA = 1 << PA0 | 1 << PA1 | 1 << PA2 | 1 << PA2;         // akzeptabel

DDRA = (1 << PA0) | (1 << PA1) | (1 << PA2) | (1 << PA2); // besser

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
    if(    ( A+10 > c )
        || ( B+25 > c ) )
      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:
    if(    A+10 > c
        || B+25 > c )
      d = 0;

oder je nach Geschmack auch
    if(A+10 > c ||
       B+25 > c)
      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:
#define DATA_MASK 0x07

if((PINA & DATA_MASK) == 5)  // richtig
{...}

if(PINA & DATA_MASK == 5)    // logisch, liefert aber nicht das
{...}                        // 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 ;-)

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
  if (
    x > 0 && b > 0 && x > MAX - b ||
    x < 0 && b < 0 && x < MIN - b
  )
oder lieber
  if (
    ( (x > 0) && (b > 0) && (x > (MAX - b)) ) ||
    ( (x < 0) && (b < 0) && (x < (MIN - b)) )
  )
? Mir wäre letzteres deutlich lieber...

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Kann man das irgendwie abschalten?

Vermutlich mit -Wno-parentheses

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei GALs bestimmt nicht.


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

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jop schrieb:
> Hab gerade bei Wiki nachgeguckt.

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.