ergibt folgende Ausgabe:
address: 0022FF46 value: 4
address: 0022FF47 value: 7
Hier wird zuerst die Adresse inkrementiert und danach erst referenziert.
1
printf("%X\n",tst_int);
2
tst_int=~tst_int++;//first invert value, then increment it
Benjamin schrieb:> *tst_ptr++; // first increment address, then dereference it
Mit ausreichenden Warnungs-Einstellungen sollte dir der Compiler
hier sagen, dass dieser Stern nutzlos ist: das Ergebnis des
Dereferenzierens des Zeigers wird verworfen.
> tst_int = ~tst_int++; //first invert value, then increment it
Undefined behaviour. (Standard § 6.5, Absatz 2)
Vielen Dank für Deine Antwort. Damit hätte ich jetzt nicht gerechnet,
diese Sprache macht mich noch fertig...
Mit -Wall habe ich die Warnung für Nummer 2 jetzt bekommen.
Das erste wird bei mir aber doch nicht verworfen, sondern er
dereferenziert den zeiger doch, nachdem er inkrementiert wurde?
foo.c:10:1: Warnung: berechneter Wert ist unbenutzt [-Wunused-value]
4
foo.c:14:9: Warnung: Operation auf »tst_int« könnte undefiniert sein [-Wsequence-point]
5
foo.c:5:15: Warnung: Variable »tst_int2« wird nicht verwendet [-Wunused-variable]
Benjamin schrieb:> Damit hätte ich jetzt nicht gerechnet, diese Sprache macht mich noch> fertig...
Naja, Prä- und Postfix-Inkrement oder -Dekrement wirken immer
irgendwann vor bzw. nach der gesamten Berechnung des Ausdrucks.
Der Standard lässt aber offen, in welcher Reihenfolge der Compiler
die einzelnen Bestandteile der Zuweisungsanweisung bewertet, d. h.
sicher, dass der Zeiger (infolge des ++-Operators) auch tatsächlich
erhöht worden ist, kann man sich erst nach der Zuweisungsanweisung
sein. Ob der Zeiger vor der Zuweisung selbst oder erst danach
inkrementiert wird, ist eben nicht definiert.
Es ist daher grundsätzlich eine schlechte Idee, irgendetwas, das auf
der rechten Seite einer Zuweisung einen Prä- oder Postfix-Operator
hat, ebenfalls nochmal auf der linke Seite der Zuweisung stehen zu
haben.
Benjamin schrieb:> Das erste wird bei mir aber doch nicht verworfen, sondern er> dereferenziert den zeiger doch, nachdem er inkrementiert wurde?Oliver S. schrieb:> Mit dem dereferenzierten Wert passiert dann aber nichts.
Es gibt übrigens einen Fall, bei dem man sowas trotzdem zuweilen
gebrauchen kann: wenn der Zeiger auf ein Objekt zeigt, welches als
“volatile” markiert ist. Das kann dann beispielsweise ein IO-Register
eines Controllers sein, und bei dem ist es schon wichtig, dass es
auch wirklich gelesen wird, denn das Lesen kann ja in der Hardware
Seiteneffekte haben (bspw. das Rücksetzen einer Interruptbedingung).
Wenn man sowas wirklich braucht, dann sollte man das aber auch
explizit hinschreiben:
1
(void)*udr_pointer;// read UDR to clear any pending interrupt
Der Typecast nach void macht dabei klar, dass es die volle Absicht
des Programmierers war, den Wert zu verwerfen.
>Es ist daher grundsätzlich eine schlechte Idee, irgendetwas, das auf>der rechten Seite einer Zuweisung einen Prä- oder Postfix-Operator>hat, ebenfalls nochmal auf der linke Seite der Zuweisung stehen zu>haben.
Stimmt, das kommt mir wieder bekannt vor. Nochmal danke für die
ausführliche Antwort.
Benjamin schrieb:> Das erste wird bei mir aber doch nicht verworfen, sondern er> dereferenziert den zeiger doch, nachdem er inkrementiert wurde?
Nein. Es ist das Postinkrement.
Es wird erst dereferenziert und dann wird der Zeiger inkrementiert. (der
Zeiger, nicht der Wert)
DirkB schrieb:> Es wird erst dereferenziert und dann wird der Zeiger inkrementiert. (der> Zeiger, nicht der Wert)
Du kannst nur sicher sein, daß der nicht-inkrementierte Zeiger
dereferenziert wird. Genaue Ausführung und Reihenfolge von
Inkremetierung und Dereferenzierung sind nicht definiert. Genau deshalb
ist
>i = i++;
undefined behaviour.
Oliver
Peter Dannegger schrieb:> Man kann aber schreiben:> i = 0 ? 0 : i++;
Nein. Zwischen i und i++ liegt kein sequence point. Der liegt zwischen
der ersten 0 und dem Rest.
Zulässig wäre beispielsweise
i = i++ ? i : 0;
Jörg Wunsch schrieb:> Wenn man sowas wirklich braucht, dann sollte man das aber auch> explizit hinschreiben:> (void)*udr_pointer; // read UDR to clear any pending interrupt>> Der Typecast nach void macht dabei klar, dass es die volle Absicht> des Programmierers war, den Wert zu verwerfen.
Hmm, in meinem Fall würde es eher davon ablenken. Ich würde mich halt
fragen, wozu dieser unsinnige Cast da sein soll, statt warum das
Ergebnis der Dereferenzierung verworfen wird. ;-)
Benjamin schrieb:> unsigned char tst_int2 = 7;> unsigned char tst_int = 4;> unsigned char *tst_ptr = &tst_int;>> printf("address: %p\tvalue: %d\n", tst_ptr, *tst_ptr);> *tst_ptr++; // first increment address, then dereference it> printf("address: %p\tvalue: %d\n", tst_ptr, *tst_ptr);
Die Anweisung *tst_ptr++ inkrementiert die Speicherstelle! Das die Zahl
7 dabei rauskommt ist Glück. Ist zufällig der Inhalt von tst_int2.
Wenn Du den Inhalt von tst_int ändern möchtest, musst Du klammern:
(*tst_ptr)++
Ergibt dann 5.