Verhalten von prinft in Kombination mit increment(i++/++i) in C

Wie ihr in der Übung bereits bemerkt habt, hat printf ein seltsames Verhalten, wenn man in den Parametern mehr als ein increment nutzt.
Hier nochmal das Beispiel aus der Übung:

#include <stdio.h>

void main(){
int i=0;
printf("%i %i %i\n", i++, i++, i++);
int i=0;
printf("%i %i %i", ++i, ++i, ++i);
}

Man würde nun erwarten, dass die Ausgabe wie folgt lautet:

0 1 2
1 2 3

Die Ausgabe dieses Programms war in der Übung:

2 1 0
3 3 3

Man kann sich ruhig einige Sekunden nehmen, dies zu betrachten.
i selbst ist im Grunde nur eine Adresse, an der etwas abgelegt werden kann – der Wert von i.
Nach i++ hält i nach wie vor dieselbe Adresse, aber der Wert von i wurde um 1 erhöht.

Der printf Befehl wertet solche increment Operationen aus, bevor die Ausgabe mit den entsprechenden Werten der Variablen konstruiert wird.
Dies zeigt sich an dem folgenden Beispiel.

Der Code von oben wurde leicht modifiziert:

#include <stdio.h>

void main(){
int i=0;
printf("%i %i %i\n", i++, i, i++);
int i=0;
printf("%i %i %i", ++i, i, ++i);
}

Die Ausgabe ist nun:

1 2 0
2 2 2

Warum dieses seltsame, unerwartete Verhalten?

Kurz: In C ist das Verhalten für 2 increment Operationen in einer Anweisung nicht definiert.

Lang: Der Compiler optimiert das C-Porgramm für die jeweilige Plattform, auf der er läuft.

Da für die Auswertung einer Anweisung laut C-Handbuch keine feste Reihenfolge festgelegt ist, liegt es beim Compiler, wie die obige printf Anweisung ausgewertet werden soll.

If A is not sequenced before or after B then A and B are unsequenced Evaluations A and B are indeterminately sequenced when A is sequenced either before or after B, but it is unspecified which. 13) The presence of a sequence point between the evaluation of expressions A and B implies that every value computation and side effect associated with A is sequenced before every value computation and side effect associated with B. ISO/IEC 9899:201x 5.1.2.3 §3

Hier scheinbar „von rechts nach links“.

Dieses Verhalten ist aber keinenfalls als Regel anzusehen!
Das Verhalten kann sich stark unterscheiden zwischen verschiedenen Plattformen und kann sogar Compiler abhängig sein!

Mehr als eine increment Operation in einer Anweisung hat kein eindeutig festgelegetes Verhalten zufolge!

Wie geht das richtig?

Will man ein Programm mit der Intention vom ersten Programm haben, kann man das so lösen:

#include <stdio.h>
void main(){
printf("%i %i %i\n", i++, i+1, i+2);
int i=0;
i=i+2;
printf("%i %i %i", ++i, i+1, i+2);
i=i+2;
}

Nach beiden printf Anweisungen stimmt der Zustand der Variablen noch nicht mit dem oben im ersten Beispiel überein.
Deshalb muss noch eine Zeile i=i+2 hinzugefügt werden. Nun erreichen wir nach diesen 2 Zeilen den gleichen Zustand bezüglich der Variablen wie oben, nur hier ist die Ausgabe von printf über alle Plattformen und Compiler eindeutig definiert.

Die Ausgabe ist:

0 1 2
1 2 3

Es gibt Sprachen in denen es eindeutig ist, in welcher Reihenfolge mehrere dieser increments abgearbeitet werden, aber es ist allgemein guter Stil, es nicht darauf ankommen zu lassen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.