Was macht der compiler aus sprintf(s,"%u %u",a,a++);

Gast #2082880
Lesenswert?

1
unsigned char a = 1;
2
printf("%u %u\n",a,a++);

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!
Gast #2082892
Lesenswert?

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".
Gast #2082896
Lesenswert?

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...
Gast #2082961
Lesenswert?

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.
#2082963
Lesenswert?

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
#2083136
Lesenswert?

@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.
Gast #2083325
Lesenswert?

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.
#2083348
Lesenswert?

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'))
Gast #2083374
Lesenswert?

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.
Gast #2083390
Lesenswert?

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.
Gast #2083665
Lesenswert?

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.
Gast #2084421
Lesenswert?

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.
#2084527
Lesenswert?

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren