Ausgabe ist:
2 1 anstelle von 1 2
Warum? Ich habe versucht, mir das assembler-listing anzuschauen, aber
das hilft mir als c-programmierer nicht weiter. Meine Vermutung ist,
dass beim Aufruf vom printf-befehl zuerst die argumente
verarbeitet/berechnet werden.
Dann müsste ich allerdings 2 2 als Ausgabe erhalten.
Ich stehe auf dem schlauch!
Danke für eure Hilfe!
a++ ist der Postfixoperator. Erst wird der Wert verarbeitet, dann
inkementiert.
++a ist der Prefixoperator. Der Wert wird erst inkrementiert und dann
verarbeitet.
Da die Elemente von rechts nach links auf den Stack gelegt werden ist
die Ausgabe nunmal "2 1".
Sebihepp schrieb:> Da die Elemente von rechts nach links auf den Stack gelegt werden
?!? Wirklich?
ich dachte, dass wenn ich in printf formatierte ausgaben in den string
packe "von links nach rechts" dann werden die zugehörigen Argumente auch
"von links nach rechts" angegeben, genauso auch die Ausgabe...
lag ich da falsch? Ich denke nicht oder? Das mit dem post oder präfixop.
kenne ich. Aber die umgekehrte Reihenfolge hab ich immer noch nicht
verstanden...
Sie werden in der Reihenfolge ausgegeben, die dort steht. Aber beim
Aufruf der Funktion werden sie "von rechts" auf den Stack gepackt und in
der Funktion entsprechend wieder abgeräumt.
Das kannst Du mit
Peter Dannegger schrieb:> Der Kommaoperator muß den Wert des letzten Ausdrucks zurückgeben.> Aber wann er die Ausdrücke berechnet, ist undefiniert.
sprintf(s,"%u %u",a,a++);
aber hierbei handelt es sich doch nicht um ein Kommaoperator oder etwa
doch?
Peter schrieb:> aber hierbei handelt es sich doch nicht um ein Kommaoperator oder etwa> doch?
Nein.
Timo P schrieb:> ich dachte, dass wenn ich in printf formatierte ausgaben in den string> packe "von links nach rechts" dann werden die zugehörigen Argumente> auch "von links nach rechts" angegeben, genauso auch die Ausgabe...>> lag ich da falsch?
Ja. Die Reihenfolge ist in C nicht spezifiziert. Mit anderen Worten: Du
darfst von keiner spezifischen Reihenfolge ausgehen, da das jeder
Compiler tun kann, wie er will.
Peter Dannegger schrieb:> Der Kommaoperator muß den Wert des letzten Ausdrucks zurückgeben.> Aber wann er die Ausdrücke berechnet, ist undefiniert.
Das ist nicht der Kommaoperator, das Komma trennt hier schlicht nur die
Funktionsargumente.
Die Reihenfolge, in der die Funktionsargumente ausgewertet werden (bevor
die Funktion dann aufgerufen wird) ist meines Wissens undefiniert. Hier
wird halt das letzte Argument ausgewertet (Postfix, d.h. Rückgabe = 1,
dann wird a inkrementiert) und dann das vorletzte (nun ist aber a schon
2).
viele Grüße,
Simon
Simon Budig schrieb:> Die Reihenfolge, in der die Funktionsargumente ausgewertet werden> (bevor die Funktion dann aufgerufen wird) ist meines Wissens> undefiniert.
-pedantic: Nicht undefiniert, sondern unspezifiziert.
@Autor: Timo P (Gast)
wozu braucht man so ein Konstrukt ..
> unsigned char a = 1;> printf("%u %u\n",a,a++);
.. außer um zu schauen, ob oder was der Compiler draus macht, bzw.
prüfen zu lassen ob der Ausdruck syntaktisch verarbeitbar ist?
Oder hast du ernsthaft vor, solche unverständlichen (nicht sinnvol
lesbaren) Codezeilen in irgend einem Stückchen Software zu verstecken?
Wartbar ist sowas allemale nicht.
Das war zumindest früher nicht spezifiziert.
Ich kenne einen Fall, daß durch so ein Konstrukt:
(if ((*pc++ == '0') && (*pc == '0'))
locker 120.000 DM Schaden entstanden sind. Wurde von MSC 5.0 so
übersetzt wie gewünscht, MSC 6.0 hat dann aber leider den increment nach
hinten gezogen. Dadurch wurde 2 mal das erste Zeichen verglichen.
Pech daß diese 2 Zeichen der Returncode der Authorisierungszentrale für
eine Reihe von Geldautomaten waren und die dann munter ausgezahlt hat
weil er '00' verstanden hat (auszahlen) aber tatsächlich '04' kam (Karte
einziehen, Manipulationsverdacht).
Eine Bande hatte das spitz gekriegt und munter mit geklauten Karten die
längst gesperrt waren Kohle abgehoben.
Interessant. Im Gegensatz zum Komma in Parameterlisten(!) sind die
Operatoren && und || nämlich sequence points, d.h. das Verhalten ist in
diesem Fall durchaus definiert und der Compiler darf es nicht ganz nach
hinten ziehen.
Anders sähe es da aus:
if ((*pc++ == '0') & (*pc == '0'))
The order of evaluation of the arguments to a function call is unspecified.
Lässt man das obige Beispiel in einem C-Interpreter laufen (hier CINT),
dann kommt "1 1" raus, also da wird es von links nach rechts
interpretiert.
Hermann-Josef
U.R. Schmitt schrieb:> Das war zumindest früher nicht spezifiziert.> Ich kenne einen Fall, daß durch so ein Konstrukt:> (if ((*pc++ == '0') && (*pc == '0'))> locker 120.000 DM Schaden entstanden sind. Wurde von MSC 5.0 so> übersetzt wie gewünscht, MSC 6.0 hat dann aber leider den increment nach> hinten gezogen. Dadurch wurde 2 mal das erste Zeichen verglichen.> Pech daß diese 2 Zeichen der Returncode der Authorisierungszentrale für> eine Reihe von Geldautomaten waren und die dann munter ausgezahlt hat> weil er '00' verstanden hat (auszahlen) aber tatsächlich '04' kam (Karte> einziehen, Manipulationsverdacht).> Eine Bande hatte das spitz gekriegt und munter mit geklauten Karten die> längst gesperrt waren Kohle abgehoben.
Hast du dafür eine Quelle? Das wäre ein prima Beispiel für "sauberes
Programmieren". Hätte man *pc==0 && *(pc+1)==0 geschrieben wäre alles
gut gegangen.
U.R. Schmitt schrieb:> Ich kenne einen Fall, daß durch so ein Konstrukt:> (if ((*pc++ == '0') && (*pc == '0'))> locker 120.000 DM Schaden entstanden sind. Wurde von MSC 5.0 so> übersetzt wie gewünscht, MSC 6.0 hat dann aber leider den increment nach> hinten gezogen.
Dann war ein Bug in MSC 6.0 oder an dieser Geschichte stimmt etwas
nicht. Ich sehe nicht, wie hier das Inkrement nach hinten (wohin?)
gezogen werden könnte.
doch g schrieb:> Hast du dafür eine Quelle? Das wäre ein prima Beispiel für "sauberes> Programmieren". Hätte man *pc==0 && *(pc+1)==0 geschrieben wäre alles> gut gegangen.
Wenn schon, dann "pc[0]==0 && pc[1]==0". Davon abgesehen rettet einen
sauberes Programmieren auch nicht vor Bugs im Compiler.
Die Bindungsstärken sind zwar eindeutig bei *pc++, aber *(pc++) ist
deutlicher - (*pc)++ soll es ja nicht sein.
Oder so:
if (*(pc++) == 0)
if (*pc == 0)
...
Hier wird auch ersichtlich, dass nur die erste Anweisung unbedingt
ausgeführt wird. Das kann in verketteter Logik m. E. genauso passieren.
Ein weiteres ++ sollte man sich dann besser verkneifen, außer, man
braucht pc hinterher nicht mehr.
df1as schrieb:> Oder so:>> if (*(pc++) == 0)> if (*pc == 0)> ...>> Hier wird auch ersichtlich, dass nur die erste Anweisung unbedingt> ausgeführt wird. Das kann in verketteter Logik m. E. genauso passieren.
Ein Programm leserlich zu schreiben ist eine Sache, aber als "Publikum"
sollte man diejenigen anpeilen, die von C mindestens eine grundlegende
Ahnung haben. Auf logische Operatoren wie && und || zu verzichten nur
weil ein C-unbefleckter die nicht verstehen könnte geht definitiv zu
weit.
Und bei Verzicht auf diese Operatoren kommt bei allem ausser trivialen
Bedingunen eine Wust von verschachtelten ifs raus und damit das
Gegenteil von leserlich.
Andreas B. schrieb:> Ich sehe nicht, wie hier das Inkrement nach hinten (wohin?)> gezogen werden könnte.
Da wird nichts "nach hinten gezogen". Es ist einfach vom Standard
nicht definiert, wann das Inkrement passiert außer, dass es mit
dem Erreichen des nächsten "sequence points" vollzogen sein muss.
Peter schrieb:> Peter Dannegger schrieb:>> Der Kommaoperator muß den Wert des letzten Ausdrucks zurückgeben.>> Aber wann er die Ausdrücke berechnet, ist undefiniert.>> sprintf(s,"%u %u",a,a++);>> aber hierbei handelt es sich doch nicht um ein Kommaoperator oder etwa> doch?
Stimmt, Du hast recht.
Der Kommaoperator ist ein Sequence point, d.h. es muß von links nach
rechts gearbeitet werden.
Also ist das Komma in einer Argumentenliste kein Kommaoperator.
"Note that a function call f(a,b,c) is not a use of the comma operator
and the order of evaluation for a, b, and c is unspecified."
Peter