Variablen erstellung nimmt keinen Einfluss auf den Stack



  • 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; oder

    
    

    falls `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.

    [...]

    1. 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.


  • 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), dass d nicht auf ein Hardware-Register gemappt ist. Welchen Sinn hat es dann d 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), dass d nicht auf ein Hardware-Register gemappt ist. Welchen Sinn hat es dann d 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), dass d nicht auf ein Hardware-Register gemappt ist. Welchen Sinn hat es dann d 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.)


Anmelden zum Antworten