Variablen erstellung nimmt keinen Einfluss auf den Stack
-
Der Compiler darf lokale Variabeln nach belieben auf dem Stack speichern. Soweit ich weiss wird im C-Standard das Wort "Stack" gar nie verwendet, du bekommst also keine Garantie wie das Stacklayout aussehen wird.
GCC hat eine eingebaute Heuristik (habe deren Namen vergessen), durch die lokale Buffer vor alle anderen Variabeln geschoben wird, damit man bei einem Buffer Overflow nicht die lokalen Variabeln ueberschreiben kann.
-
Andromeda schrieb:
^^ etwa so. Wenn b volatile ist, MUSS der Compiler sie jetzt anlegen.
nein, muss er nicht, der Compiler kann auch das optimieren zu
while(1);
falls
int b=1;
oderfalls
int b=5;
der Compiler wird nur etwas auf dem Stack legen, wenn es braucht.
-
supertux schrieb:
Andromeda schrieb:
^^ etwa so. Wenn b volatile ist, MUSS der Compiler sie jetzt anlegen.
nein, muss er nicht, der Compiler kann auch das optimieren zu
while(1);
falls
int b=1;
oderfalls `int b=5;
`
Du täuschst dich.
"volatile" sagt dem Compiler, dass die Variable irgendwelchen Einflüssen unterliegt, von denen er keine Kenntnis hat. Z.B. dass sie von einer Interrupt-Routine, oder einem anderen Thread verändert wird.
Bei jedem Zugriff muss er die Variable daher immer neu aus ihrer Speicherzelle lesen.
Wegoptimieren darf er sie nur dann, wenn ihr Inhalt egal ist, z.B in Ausdrücken wie: if (b==5 || 5!=b)
-
deshalb habe ich nicht
volatile
in meinem Beispiel geschrieben, aber es stimmt, meine Antwort war nicht ganz passend.Dennoch glaube ich nicht, dass der Standard explizit sagt, dass volatile Variablen auf den Stack landen müssen.
-
supertux schrieb:
deshalb habe ich nicht
volatile
in meinem Beispiel geschrieben, aber es stimmt, meine Antwort war nicht ganz passend.Dennoch glaube ich nicht, dass der Standard explizit sagt, dass volatile Variablen auf den Stack landen müssen.
Soweit mir bekannt ist, benötigt die C-spec keinen Stack. Wo lokale Variablen sind, ist IMHO implementation-defined.
-
Andromeda schrieb:
Wegoptimieren darf er sie nur dann, wenn ihr Inhalt egal ist, z.B in Ausdrücken wie: if (b==5 || 5!=b)
Der Ausdruck ist nicht Atomar, also sollte hier doch auch nichts wegoptimiert werden?
-
volat schrieb:
Der Ausdruck ist nicht Atomar, also sollte hier doch auch nichts wegoptimiert werden?
b==5 || 5!=b b || !b 1
Sowas kann ein Compiler noch zur Kompilierzeit erkennen und wegoptimieren.
EDIT: Ich sollte keinen Code schreiben kurz nach dem Aufstehen ...
-
Ja, aber es ging um volatile - da muss der Compiler davon ausgehen, dass sich der Wert von b zwischen der Auswertung von b==5 und der von 5!=b ändert.
-
SG1 schrieb:
Ja, aber es ging um volatile - da muss der Compiler davon ausgehen, dass sich der Wert von b zwischen der Auswertung von b==5 und der von 5!=b ändert.
Vielleicht garantieren Compiler so etwas, aber wie soll der Standard das vorschreiben? Wenn die Adresse der Variablen nirgendwo genommen wird, gibt es auch keine Möglichkeit ohne undefiniertes Verhalten indirekt an diese zu herankommen, also darf der Compiler nach meinem Sprachverständnis ein
volatile
bei einer lokalen Variablen unter Umständen ignorieren.
-
ISO/IEC 9899:TC3, 6.7.3 §6 schrieb:
An object that has volatile-qualified type may be modified in ways unknown to the
implementation or have other unknown side effects. Therefore any expression referring
to such an object shall be evaluated strictly according to the rules of the abstract machine,
as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the
object shall agree with that prescribed by the abstract machine, except as modified by the
unknown factors mentioned previously.116) What constitutes an access to an object that
has volatile-qualified type is implementation-defined.[...]
- A volatile declaration may be used to describe an object corresponding to a memory-mapped
input/output port or an object accessed by an asynchronously interrupting function. Actions on
objects so declared shall not be ‘‘optimized out’’ by an implementation or reordered except as
permitted by the rules for evaluating expressions.
- A volatile declaration may be used to describe an object corresponding to a memory-mapped
-
SG1 schrieb:
Ja, aber es ging um volatile - da muss der Compiler davon ausgehen, dass sich der Wert von b zwischen der Auswertung von b==5 und der von 5!=b ändert.
Theoretisch schon, doch dann hätte der logische Ausdruck (b==5 || 5!=b) eine abweichende Semantik, da im Grunde zwei verschiedene b's benutzt würden.
Aber andererseits kann der bloße Lesezugriff auf b eine Aktion auslösen, wenn b auf ein Hardware-Register gemappt ist. Das spricht dann wieder gegen eine Wegoptimierung.
-
Andromeda schrieb:
Aber andererseits kann der bloße Lesezugriff auf b eine Aktion auslösen, wenn b auf ein Hardware-Register gemappt ist. Das spricht dann wieder gegen eine Wegoptimierung.
ja, aber wenn du sowas hast
void foo(void) { volatile int d = 5; while(d == 5); }
wird das nie passieren, auch mit dem
volatile
, da sieht jeder (und auch der Compiler), dassd
nicht auf ein Hardware-Register gemappt ist. Welchen Sinn hat es dannd
nicht wegzuoptimieren?Wenn du aber sowas hättest
void foo(void) { volatile uint32_t *d = (void*) 0xdeadbeef; *d = 5; while(*d == 5); }
wäre was anders. Da wird der Compiler garantiert
d
nicht wegoptimieren.
-
supertux schrieb:
Andromeda schrieb:
Aber andererseits kann der bloße Lesezugriff auf b eine Aktion auslösen, wenn b auf ein Hardware-Register gemappt ist. Das spricht dann wieder gegen eine Wegoptimierung.
ja, aber wenn du sowas hast
void foo(void) { volatile int d = 5; while(d == 5); }
wird das nie passieren, auch mit dem
volatile
, da sieht jeder (und auch der Compiler), dassd
nicht auf ein Hardware-Register gemappt ist. Welchen Sinn hat es dannd
nicht wegzuoptimieren?Wenn du aber sowas hättest
void foo(void) { volatile uint32_t *d = (void*) 0xdeadbeef; *d = 5; while(*d == 5); }
wäre was anders. Da wird der Compiler garantiert
d
nicht wegoptimieren.Naja, das sind alles irgendwie Grenzfälle die wir hier besprechen.
Es gibt Toolchains da kann man dem Linker/Relocator explizit sagen, wo er welche Variable hintun soll. Das geht entweder über #pragmas oder über eine separate Steuerdatei. Letztere wird von der IDE erzeugt und hat mit dem C-Compiler selbst nichts mehr zu tun. Der macht den Object-Code und ein anderes Tool läuft danach drüber und ordnet die Variablen bestimmten Speicherbereichen, Steuerregistern und digitalen I/Os zu. Sowas hatte ich mal bei Keil oder irgendeinem Renesas-Ding.
Langer Rede kurzer Sinn: ich wette, dass die meisten Compiler niemals volatile-Variablen wegoptimieren. Egal, in welcher Konstellation sie auch auftauchen.
-
supertux schrieb:
void foo(void) { volatile int d = 5; while(d == 5); }
wird das nie passieren, auch mit dem
volatile
, da sieht jeder (und auch der Compiler), dassd
nicht auf ein Hardware-Register gemappt ist. Welchen Sinn hat es dannd
nicht wegzuoptimieren?Doch, macht Sinn:
int *pd; void bar(void) { *pd++; } void foo(void) { volatile int d = 5; pd = (int *) &d; while(d == 5); }
Wenn jetzt bar() durch nen Interrupt aufgerufen wird, kann ja Durchgriff über die Referenz erfolgen.
Weil der Compiler nicht wissen kann, wohin der Linker das Zeug tut, darf er das sowieso nicht auflösen (HW-Regs). Und zudem kann immer was zwischenreinhauen, auch wenn's von "ganz normalen" Stellen kommt.
-
Du kannst nicht schreiben "Doch, macht Sinn", wenn du dich auf ein anderes Beispiel beziehst.
(Also du kannst schon, aber es macht halt keinen Sinn.)