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
volatilestructframe*bus_frame;
In bus.h wird der Pointer als extern deklariert:
1
externvolatilestructframe*bus_frame;
In bridge.c wird nun dieser Pointer in einer Schleife verwendet:
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
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)
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
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.
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.
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.