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


von Tobias (Gast)


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:
1
volatile struct frame * bus_frame;

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

In bridge.c wird nun dieser Pointer in einer Schleife verwendet:
1
void bridge_mainloop(void)
2
{
3
    while (1){
4
        if( bus_frame->isnew == 1){
5
            bus_frame->isnew = 0;
6
        }
7
        wdt_reset();
8
    }
9
}


Der gcc generiert mir aus der Schleife folgendes:
1
void bridge_mainloop(void)
2
{
3
     2ba:   e0 91 57 02     lds r30, 0x0257
4
     2be:   f0 91 58 02     lds r31, 0x0258
5
     2c2:   01 c0           rjmp    .+2         ; 0x2c6 <bridge_mainloop+0xc>
6
    while (1){
7
        if( bus_frame->isnew == 1){
8
            bus_frame->isnew = 0;
9
        }
10
        wdt_reset();
11
     2c4:   a8 95           wdr
12
}
13
14
void bridge_mainloop(void)
15
{
16
    while (1){
17
        if( bus_frame->isnew == 1){
18
     2c6:   85 a9           ldd r24, Z+53   ; 0x35
19
     2c8:   81 30           cpi r24, 0x01   ; 1
20
     2ca:   e1 f7           brne    .-8         ; 0x2c4 <bridge_mainloop+0xa>
21
            bus_frame->isnew = 0;
22
     2cc:   15 aa           std Z+53, r1    ; 0x35
23
     2ce:   e0 91 57 02     lds r30, 0x0257
24
     2d2:   f0 91 58 02     lds r31, 0x0258
25
     2d6:   f6 cf           rjmp    .-20        ; 0x2c4 <bridge_mainloop+0xa>
26
27
000002d8 <bridge_tick>:
28
        wdt_reset();
29
    }
30
}

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

von Johannes M. (johnny-m)


Lesenswert?

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

von Karl H. (kbuchegg)


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)

von Johannes M. (johnny-m)


Lesenswert?

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

von Karl H. (kbuchegg)


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 :-)

von Tobias (Gast)


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

von (prx) A. K. (prx)


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.

von Karl H. (kbuchegg)


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.
1
int * (* (*fp1) (int) ) [10];
2
3
                                           fp1 ist
4
5
rechts ist nichts, also links         *    ein Pointer
6
links vom * ist (, also umdrehen
7
damit ist die Klammer um (*fp1)
8
erledigt und es geht wieder los, indem
9
man einmal nach rechts geht
10
rechts steht                        (int)  (int)  auf eine Funktion die
11
                                            einen int nimmt
12
und wieder nach links               *       die Funktion liefert einen
13
                                            Pointer               
14
links kommt wieder eine (, also umdrehen
15
damit ist (*(*fp1)(int)) abgehandelt, einmal
16
nach rechts
17
rechts steht [, also ein Array       [10]   auf ein Array
18
weiter links                         *      von Pointern
19
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.

von Johannes M. (johnny-m)


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.

von Joachim (Gast)


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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.