PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C Klammerung



Siro
18.10.2013, 15:53
Hallo zusammen, noch eine kurze Frage zum Wochenende

Ich bin mal wieder auf die Nase gefallen und habe lange nach einem Fehler gesucht.
Ich verstehe nicht wo der Unterschied zwischen diesen beiden Abfragen liegt, dass es mal geht und mal nicht.



int main(void)
{ int a,b,result;

a = 0x01;
b = 0x80;

if (a & b == 0) /* Bitweises UND, es müste 0 rauskommen */
{
result = TRUE;
} else
{
result = FALSE; /* Ergebis ist aber FALSE */
}


a = -3;
b = +3;
if (a + b == 0)
{
result = TRUE; /* Ergebnis ist TRUE, hier stimmt es */
} else
{
result = FALSE;
}

}

Ich weis, (falsch: man hat mir gesagt) ich muss hier nochmal Klammern.
if ((a & b) == 0)

als alter Pascal Freak, ist das für mich natürlich überhaupt nicht einleuchtend, weil da brauche ich garkeine Klammern bei diesem simplen Gebilde ;)

Aber ich möchte einfach nur verstehen warum ich hier nochmals Klammern setzen muss.
Eine if Abfrage muss generell in Klammern, okay ist halt so festgelegt, aber wozu die anderen Klammern.
Bei der Addition funktioniert es ja auch ohne, bei dem Bitweisen UND nicht mehr. :(

Dank Euch für Infos.
Siro

Bátorság
18.10.2013, 16:03
Das hängt alles von der Abarbeitungsrichtung und der Rangordnung der Operatoren ab. Guck mal hier: http://manderc.manderby.com/operators/paranthesesoperator/index.php

Siro
18.10.2013, 18:55
Danke Dir erstmal für den Link:

Verstanden hab ich es nicht wirklich.
Die Abarbeitungsrichtung ist demnach von links nach rechts bei einem Bitweisen AND
== hat den Rang 10
& hat den Rang 4

aber was sagt mir das jetzt ?

wie dem auch sei:
Laut Assembler Code hat mein Compiler result = FALSE daraus gemacht.
Er hat die AND Funktion also garnicht erst ausgeführt.
wie kommt er darauf, er weis dorch garnicht was rauskommt.

es sei denn, er hat es wie folgt aufgelöst ?
if (a & (b==0))

wenn also b==0 ist, muss a zwangsläufig nach dem AND auch 0 sein und damit ist das Ergebnis des Vergleichs immer 0
und deshalb erzeugt er nur den Code für result = FALSE

Liege ich da ungefähr richtg ?

TheDarkRose
18.10.2013, 19:40
Siehe Operator Precedence (http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence). == hat eine höhere Wertung als & und wird somit als erster evaluiert. Generell, weiß man es nicht, oder will sich nicht darauf verlassen, immer Klammern setzen. Schadet nie und schützt vor überraschenden Änderungen in der Zukunft, oder komischen Compilern.

malthy
18.10.2013, 19:59
und "+" bindet seinerseits stärker als "==", deswegen das Ergebnis deiner zweiten Abfrage. Hätte ich jetzt auch nicht gewusst, insofern war's lehrreich :-).

radbruch
18.10.2013, 20:32
Hallo

Obwohl man die Bindung oder Rangfolge der Operatoren (http://openbook.galileocomputing.de/c_von_a_bis_z/029_c_anhang_a_001.htm) bei Unsicherheit ja schnell mal nachschlagen kann setze ich trotzdem immer ein paar Klammern mehr, weil es die Lesbarkeit des Codes erhöht. Der Kompiler ignoriert überflüssige Klammern sowieso...

Gruß

mic

Siro
18.10.2013, 21:02
Okay, Danke Euch, dann hab ich es jetzt doch verstanden. Hätte nie gedacht, daß eine Zuweisung VOR einer Operation stehen könnte.
Ich dachte immer, erstmal rechnen und dann zuweisen. Naja man lernt halt nie aus. Ich denke auch, es ist "einfacher" ein paar Klammern mehr zu setzen,
nicht das erste Mal, daß ich mir dadurch das Leben schwer mache. Dann habt noch ein Bugfreies Wochenende ;)

malthy
18.10.2013, 21:13
Hätte nie gedacht, daß eine Zuweisung VOR einer Operation stehen könnte.

Hm, versteh dich jetzt nicht so ganz. Eigentlich werden ja nur die Wahrheitswerte von (a & b == 0) und (a + b == 0) berechnet. Und weil die Operatoren & und + eben einmal stärker und einmal schwächer als == binden, fällt das Ergebnis eben so aus, wie es es ausfällt.

Siro
18.10.2013, 22:53
sorry, das war ja jetzt auch falsch ausgedrückt. Das ist natürlich keine Zuweisung, sondern eine Abfrage.
das mit dem Binden ist schon merkwürdig (verwirrend) für mich, weil das gab es in der Form nicht bei Pascal/Delphi.

Klebwax
19.10.2013, 00:23
sorry, das war ja jetzt auch falsch ausgedrückt. Das ist natürlich keine Zuweisung, sondern eine Abfrage.

Eigentlich nicht. == ist ein genau so ein Operator wie &. So etwas wie einen Abfrageoperator gibt es in C nicht. == ist der Vergleichsoperator und liefert TRUE, wenn die Werte auf beiden Seiten gleich sind.

das mit dem Binden ist schon merkwürdig (verwirrend) für mich, weil das gab es in der Form nicht bei Pascal/Delphi.
Aber natürlich gibt es das, wie überall, wo mehrere Operationen in einem Ausdruck zulässig sind. Ein einfacher, bekannter Fall ist: Punktrechnung geht vor Strichrechnung (d.h. ein * bindet stärker als ein +. Es gibt aber noch weitere Regeln für Brüche. Da es aber in C (und eigentlich allen Programmiersprachen) viel mehr Operatoren als nur die rein mathematischen gibt, sind die Bindungsregeln auch komplexer. Daher ist
Obwohl man die Bindung oder Rangfolge der Operatoren bei Unsicherheit ja schnell mal nachschlagen kann setze ich trotzdem immer ein paar Klammern mehr, weil es die Lesbarkeit des Codes erhöht. Der Kompiler ignoriert überflüssige Klammern sowieso... eine gute Strategie.

Ich denke, das Problem liegt an einer anderen Stelle. Ein if in C funktioniert etwas anders, als in manchen anderen Sprachen. Ist der Wert der Klammer hinter einem if TRUE, wird der nächste Befehl ausgeführt. Ob sich der Wert in der Klammer durch einen Vergleichsoperator, durch einen anderen Operator oder durch eine beliebig komplexe Aufreihung von Operatoren ergibt (oder ob da einfach der Wert 1 steht) ist egal. Deswegen ist ein gängiger Fehler in C, daß man statt if ( a == 3) die Zuweisung if ( a = 3) schreibt. Das zweite ist in C sytaktisch korrekt, aber meist nicht das, was man will.

MfG Klebwax

Peter(TOO)
19.10.2013, 00:31
Hallo Siro,

Du solltest dir noch etwas angewöhnen.

Schreibe immer:
if (0 == a)
und nie
if (a == 0)

Rein logisch ist das identetisch, aber in C, und ein paar anderen Sprachen, gibt es den Unterschied bei = (zuweisung) und == (gleich).
Wenn du die Konstante immer links schreibst und du versehentlich
if (0 = a)
tippst, wird dich der Compiler anmotzen!

if (a = 0)
ist aber auch gültige Syntax, macht aber etwas ganz anderes als
if (a == 0)

MfG Peter(TOO)

oberallgeier
19.10.2013, 09:10
... Siro ... solltest dir noch etwas angewöhnen ...Bin zwar nicht Siro - aber wird mir sicher auch gut tun. Denn DAS ist ein Tipp, wie ich es liebe. Weil er die Zuverlässigkeit nächtlich-müden Programmzeilenschreibens ziemlich erhöht!

Es lebe das Kommutativgesetz!

Siro
19.10.2013, 09:23
Ein if in C funktioniert etwas anders, als in manchen anderen Sprachen.

Da hast Du recht, vermutlich liegt da mein Problem:
Eine Abfrage wie if (a) würde in anderen Sprachen angemeckert werden, weil ein Operator fehlt.
Bei if (a=3) handelt es sich quasi um ein Doppelschritt, wenn ich das so nennen darf.
Erst wird a der Wert 3 zugewiesen und dann wird verglichen ob das Ergebnis ungleich 0 ist.
Vermutlich wird das sogar wegoptimiert, weil 3 immer TRUE ist.

Jezt wird mir auch langsam klar warum es == gibt. Das bedeutet nicht etwa "besonders gleich" :)
sondern lediglich ein Vergleich ohne jegliche Zuweisung.

Mit dem Vertauschen sieht zwar erstmal etwas "ungewohnt" aus, hat aber durchaus seinen Sinn.
Einer Konstanten kann ich ja nichts zuweisen. Leuchtet ein.

TheDarkRose
19.10.2013, 12:02
Jaja, die Yoda Conditions (http://www.codinghorror.com/blog/2012/07/new-programming-jargon.html) ^^

malthy
19.10.2013, 13:14
Jaja, die Yoda Conditions (http://www.codinghorror.com/blog/2012/07/new-programming-jargon.html) ^^

Sehr gut! "NOPping" statt "nap" gefiel mir auch gut :-).
(sorry für's off topic)

shedepe
21.10.2013, 13:18
Wenn man generell mit -Wall compiliert (Was man sowie so machen sollte) kriegt man bei den meisten Compilern auch eine Warnung wenn man schreibt
if(a = 3)

oberallgeier
21.10.2013, 13:37
Wenn man generell mit -Wall compiliert (Was man sowie so machen sollte) ...Genau das passiert mir ja - ohne jeglichem Zutun - mit dem AVRStudio 4. Und -Wall steht auch prompt im Übersetzungskommentar:


// ================================================== ==============================
/* Der aktuelle Übersetzungskommentar:
Build started 11.10.2013 at 18:10:01
avr-gcc -I"D:\D_pro-fils\compu+MC\C5_Ronny-5_etc\R5MoCo\..\R5_Lib01"
-mmcu=atmega328p -Wall -gdwarf-2 -std=gnu99
-DF_CPU=20000000UL -Os -funsigned-char -funsigned-bitfields
-fpack-struct -fshort-enums -MD -MP -MT R5MoCo.o -MF dep/R5MoCo.o.d
-c ../R5MoCo.c
avr-gcc -mmcu=atmega328p -Wl,-Map=R5MoCo.map R5MoCo.o -o R5MoCo.elf
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature
R5MoCo.elf R5MoCo.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load"
--change-section-lma .eeprom=0 --no-change-warnings -O
ihex R5MoCo.elf R5MoCo.eep || exit 0
avr-objdump -h -S R5MoCo.elf > R5MoCo.lssAVR Memory Usage
----------------
Device: atmega328p
Program: 7842 bytes (23.9% Full)
(.text + .data + .bootloader)
Data: 1554 bytes (75.9% Full)
(.data + .bss + .noinit)
Build succeeded with 0 Warnings...
================================================== ========== */