www.mikrocontroller.net

Forum: Compiler & IDEs Probleme mit volatile struct * und gcc


Autor: Tobias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich hab hier ein Problem mit den Optimierungen, die der gcc auf einen 
Pointer einer Struct anwendet:

Zum Patienten:

In bus.c wird ein Pointer auf eine Struct definiert:
volatile struct frame * bus_frame;

In bus.h wird der Pointer als extern deklariert:
extern volatile struct frame * bus_frame;

In bridge.c wird nun dieser Pointer in einer Schleife verwendet:
void bridge_mainloop(void)
{
    while (1){
        if( bus_frame->isnew == 1){
            bus_frame->isnew = 0;
        }
        wdt_reset();
    }
}


Der gcc generiert mir aus der Schleife folgendes:
void bridge_mainloop(void)
{
     2ba:   e0 91 57 02     lds r30, 0x0257
     2be:   f0 91 58 02     lds r31, 0x0258
     2c2:   01 c0           rjmp    .+2         ; 0x2c6 <bridge_mainloop+0xc>
    while (1){
        if( bus_frame->isnew == 1){
            bus_frame->isnew = 0;
        }
        wdt_reset();
     2c4:   a8 95           wdr
}

void bridge_mainloop(void)
{
    while (1){
        if( bus_frame->isnew == 1){
     2c6:   85 a9           ldd r24, Z+53   ; 0x35
     2c8:   81 30           cpi r24, 0x01   ; 1
     2ca:   e1 f7           brne    .-8         ; 0x2c4 <bridge_mainloop+0xa>
            bus_frame->isnew = 0;
     2cc:   15 aa           std Z+53, r1    ; 0x35
     2ce:   e0 91 57 02     lds r30, 0x0257
     2d2:   f0 91 58 02     lds r31, 0x0258
     2d6:   f6 cf           rjmp    .-20        ; 0x2c4 <bridge_mainloop+0xa>

000002d8 <bridge_tick>:
        wdt_reset();
    }
}

Das Problem:
Solange die if-Bedingung nicht erfuellt ist wird das Z-Register nicht 
wieder mit einer neuen Adresse geladen obwohl der Pointer als volatile 
gekennzeichnet ist.

Dieses Problem tritt nur bei -O2 und -O3 auf.

Jemand eine Idee, ob ich was falsch mache oder einfach nur der Compiler 
ein Problem hat?

Gruss, Tobias

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nicht der Pointer ist in Deiner Variante volatile, sondern das, worauf 
er zeigt!
volatile TYP ptr*
ist ein Zeiger auf ein Objekt vom Typ "volatile TYP". Wenn der Pointer 
volatile sein soll, dann muss das so aussehen:
TYP ptr volatile*

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tobias wrote:

> Solange die if-Bedingung nicht erfuellt ist wird das Z-Register nicht
> wieder mit einer neuen Adresse geladen obwohl der Pointer als volatile
> gekennzeichnet ist.


Ähm. Der Pointer ist nicht volatile.
Die Struktur auf die er zeigt ist volatile, aber die Pointer Variable 
selber ist es nicht.

volatile (und const) wirken immer auf das Teil links von ihnen (es sei 
denn link ist nichts mehr, dann wirken sie auf das Teil unmittelbar 
rechts von ihnen)

Beginne bei der Variable zu lesen und arbeite dich nach links durch (die 
tatsächliche allgemeine Leseregel ist ein klein wenig komplizierter, 
aber für diesen Fall geht es auch so):

volatile struct frame * bus_frame;

bus_frame ist also
ein Pointer
      ein Pointer auf eine Struktur
            und diese Struktur ist als Ganzes volatile



struct frame * volatile bus_frame;

bus_frame ist also
   etwas volatiles
        und zwar ein volatile Pointer
            und dieser volatile Pointer zeigt auf ein struct frame


volatile struct frame * voaltile bus_frame;

bus_frame ist also
   etwas volatiles
        und zwar ein volatile Pointer
            und dieser volatile Pointer zeigt auf ein struct frame
                und dieses struct frame ist selber volatile


struct frame volatile * voaltile bus_frame;

bus_frame ist also
   etwas volatiles
        und zwar ein volatile Pointer
            und dieser volatile Pointer zeigt auf etwas volatiles
                und dieses volatile auf das der vol. Pointer zeigt
                ist ein struct frame


            volatile struct frame * voaltile bus_frame;
und         struct frame volatile * voaltile bus_frame;

werden identisch aufgefasst aufgrund der Regel, dass volatile auch nach 
rechts wirken kann, wenn links nichts mehr ist.
(und wenn man die letzten beiden Auflösungen mal vergleicht, sind sie in 
der Tat logisch identisch)

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Karl heinz:
Und wieder ein Grund, um vor Dir auf die Knie zu fallen...;-) Wann 
erscheint noch mal Dein Buch?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:
> @Karl heinz:
> Und wieder ein Grund, um vor Dir auf die Knie zu fallen...;-) Wann
> erscheint noch mal Dein Buch?

Nie :-)

Autor: Tobias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah das war es natuerlich.

Da arbeitet man jetzt jahrelang mit C und faellt dann darueber.

Danke fuer die zwei doch sehr unterschiedlichen Antworten ;)

@Karl Heinz:
Kann man dich als lebenden Codevalidierer einstellen?

Gruss, Tobias

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Diese bescheuerte Syntax hat historische Gründe. Pointer-Qualifier wie 
"const" oder "volatile" waren vor ANSI-C nicht existent, aber links vom 
"*" ging aus syntaktischen Gründen nicht mehr, also musste der Qualifier 
rechts vom "*" untergebracht werden.

Wem das noch nicht blöd genug aussieht, der überlege sich mal, wo man 
sowas syntaktisch bei Arrays [] oder Funktionen () unterbringen musste. 
Kleiner Tip: links davon geht schon wegen type casts nicht.

Wie kbuchegg schon anmerkte. Nach links zu wandern passt hier zwar, 
stimmt aber nicht. Man muss von der Variable ausgehen und sich den 
Prioritäten der Operatoren * () [] entlang von innen nach aussen 
hangeln. Das geht folglich mal nach links, mal nach rechts. Und treibt 
bei type casts ganz besondere Blüten, weil man dort erst einmal den 
Platz des nicht vorhandenen Variablennamens finden muss.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. wrote:

> Wie kbuchegg schon anmerkte. Nach links zu wandern passt hier zwar,
> stimmt aber nicht. Man muss von der Variable ausgehen und sich den
> Prioritäten der Operatoren * () [] entlang von innen nach aussen
> hangeln.

Yep.
Das nennt sich die Rechts/Links Regel (wer googeln möchte: "C++ left 
right rule" liefert Resulate)

Fang beim Variablennamen an
Lies einmal nach rechts und dann nach links
wenn du auf eine Klammer stösst (egal ob ( oder [) dreh die Leserichtung
um. Runde Klammern bezeichnen Funktionen, eckige Klammern sind Arrays
Ist ein Klammernpaar abgearbeitet, spring aus der Klammer raus und fang 
wieder an, einmal nach rechts zu lesen.
int * (* (*fp1) (int) ) [10];

                                           fp1 ist

rechts ist nichts, also links         *    ein Pointer
links vom * ist (, also umdrehen
damit ist die Klammer um (*fp1)
erledigt und es geht wieder los, indem
man einmal nach rechts geht
rechts steht                        (int)  (int)  auf eine Funktion die
                                            einen int nimmt
und wieder nach links               *       die Funktion liefert einen
                                            Pointer               
links kommt wieder eine (, also umdrehen
damit ist (*(*fp1)(int)) abgehandelt, einmal
nach rechts
rechts steht [, also ein Array       [10]   auf ein Array
weiter links                         *      von Pointern
weiter nach links                    int    auf int


In einem Satz

int * (* (*fp1) (int) ) [10];

fp1 ist ein Pointer auf eine Funktion die einen int als Argument 
akzeptiert und einen Pointer auf ein Array von Pointern zurückliefert.

Wie war das mit dem Array? Den Pointer drauf liefert die Funktion auf 
die fp1 zeigt.
Und was ist in dem Array?   Das sind selber wieder Pointer drinnen

> bei type casts ganz besondere Blüten, weil man dort erst einmal den
> Platz des nicht vorhandenen Variablennamens finden muss.

:-)
Genau

Ich sag nur eins: typedef ist dein Freund

Es gitb übrigens auch Programme, die einem solche Typ-Monster 
auseinanderklauben und sich nach der Rechts/Links Regel durchhangeln.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:
>> Und wieder ein Grund, um vor Dir auf die Knie zu fallen...;-) Wann
>> erscheint noch mal Dein Buch?
>
> Nie :-)
Hmmm, eigentlich schade. Aber man müsste echt mal wenigstens einige 
Deiner "Aufsätze" in die Tutorials bzw. die Artikelsammlung übernehmen.

Autor: Joachim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Artikel hinter diesem Link hier in diesem Posting erklärt dieses 
Thema auch gut finde ich.


Beitrag "Re: Erklärung von "volatile""

Gruß Joachim

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.