wobei baud_t ein enum mit gültigen werten ist.
was genau bewirkt
static volatile baud_t baud
in einer Funktion?
Also durch volatile kann die Variable ja auch durch eine ISR beschrieben
werden. Aber dann muss die Variable doch in der Datei definiert werden?
static variablen in einer Funktion bleiben doch auch nur in der Funktion
sichtbar (und wird beim neuen eintreten nicht neu initialisert (wobei
eine init-funktion eh nur einmal aufgerufen werden sollte))
Alex schrieb:> was genau bewirkt> static volatile baud_t baud> in einer Funktion?
Meine Erklärungen:
Du hast den wahren Grund für das volatile da raus geschnitten. (naja...)
Der Programmierer wusste nicht was er tat. (naja)
Der Programmiere hat zwecks leichterem Debuggen die Optimierung für die
Variable abgeschaltet, und hinterher vergessen das volatile wieder raus
zu nehmen.
Hm ja wie schon geschrieben wurde, wird die statische Variabel in der
Methode nur einmal initialisiert und behält ihren Wert zwischen Aufrufen
bei. Volatile kennzeichnet die Variabel für den Compiler so das deren
Wert sich auch ohne "das Programm" ändern könnte, durch z. B. andere
Threads, Prozesse oder wie auch immer (Hardware) . Daher schließt der
Compiler die Variabel dann von den meisten Optimierungen aus. Bei nem
einfachen MC wird diese dann z. B. nicht einfach "weg-optimiert" falls
sie evtl. garnicht weiter verwendet wird.
Alex schrieb:> was genau bewirkt> static volatile baud_t baud> in einer Funktion?
baut_t ist ein enum? Es ist also kein atomic in irgend einer Form dabei?
Auf welcher Architektur soll das laufen? Es handelt sich um c? Es
handelt sich also um setBaudrate(baud_t) und nicht setBaudrate(baud_t&)?
Es passiert nichts weiter mit baud außer der Definition und dem
setBaudrate Aufruf?
>> was genau bewirkt> static volatile baud_t baud> in einer Funktion?> ...> Aber dann muss die Variable doch in der Datei definiert werden?
Wird sie. Die Variable 'baud' wird mit dem Datentyp 'baud_t' lokal
deklariert. Für baud_t existiert bestimmt irgendwo ein #define o.ä..
Zusätzlich wird sie in der Funktion 'init_uart' statisch gemacht und als
volatile gekennzeichnet.
Zeig mal die gesamte Funktion und was baud_t ist.
Arduino Fanboy D. schrieb:> Meine Erklärungen:> Du hast den wahren Grund für das volatile da raus geschnitten. (naja...)> Der Programmierer wusste nicht was er tat. (naja)> Der Programmiere hat zwecks leichterem Debuggen die Optimierung für die> Variable abgeschaltet, und hinterher vergessen das volatile wieder raus> zu nehmen.
So ist es. Höflich ausgedrückt wäre, daß in den wenigen gezeigten Zeilen
kein sinnvoller Grund für die Verwendung von volatile erkennbar ist.
Ich tippe ja auf #2 der List vom Fanboy.
Oliver
Alex schrieb:> Also durch volatile kann die Variable ja auch durch eine ISR beschrieben> werden. Aber dann muss die Variable doch in der Datei definiert werden?
ISRs sind eine mögliche Anwendung für volatile, aber nicht die einzige.
Christian G schrieb:> Hm ja wie schon geschrieben wurde, wird die statische Variabel in der> Methode nur einmal initialisiert und behält ihren Wert zwischen Aufrufen> bei. Volatile kennzeichnet die Variabel für den Compiler so das deren> Wert sich auch ohne "das Programm" ändern könnte, durch z. B. andere> Threads, Prozesse oder wie auch immer (Hardware) .
Nicht nur ändern, sondern dass sie auch durch sowas gelesen werden kann.
> Daher schließt der Compiler die Variabel dann von den meisten Optimierungen> aus.
Genauer gesagt führen alle Zugriffe auf die Variable (sowohl lesend, als
auch schreibend), die im Code stehen, zu einem entsprechenden
Speicherzugriff. Die Zugriffe müssen alle stattfinden und werden auch
nicht umsortiert.
Rolf M. schrieb:> Die Zugriffe müssen alle stattfinden und werden auch> nicht umsortiert.
Man muss allerdeings dran denken, dass
1
What constitutes an access to an object that has volatile-qualified type is implementation-defined.
und
1
Actions on objects so declared shall not be ‘‘optimized out’’ by an implementation or reordered except as permitted by the rules for evaluating expressions.
mh schrieb:> noch einige Optimierungen offen lässt.
Ja, z.B. die "Short circuit evaluation"
Oder die Addition mit einem konstanten Wert, wie 0
Die Multiplikation mit 1
Das ist so ein Kram der dennoch weg optimiert werden kann, ohne jeden
Schaden anzurichten.
mh schrieb:> is implementation-defined
Das heißt nicht "unbestimmt", o.ä.
Sondern: Schau ins Kompiler Handbuch, da ist es beschrieben.
Arduino Fanboy D. schrieb:> mh schrieb:>> noch einige Optimierungen offen lässt.> Ja, z.B. die "Short circuit evaluation"
Die ist keine Optimierung, sondern in C vorgeschriebenes Verhalten.
Das heißt, dass bei
1
inti=0;
2
volatileintj=3;
3
if(i&&j)
ein Zugriff auf j nicht stattfinden darf.
> Oder die Addition mit einem konstanten Wert, wie 0> Die Multiplikation mit 1
Da sehe ich keinen Grund, warum das bei einer volatile-Variablen
wegoptimiert werden dürfte. Ich sehe z.B. bei der Definition des
Additions-Operators nirgends eine Ausnahme für den Wert 0. Vielleicht
kann die eigentliche Addtions-Instruktion weggelasen werden, aber eine
Lese- und Schreibzugriff auf die Variable muss dennoch erfolgen.
Rolf M. schrieb:> Vielleicht> kann die eigentliche Addtions-Instruktion weggelasen werden, aber eine> Lese- und Schreibzugriff auf die Variable muss dennoch erfolgen.
Es stellt sich aber die Frage, was passiert, wenn die eigentliche
Operation aus zwei Instruktionen besteht. Wenn die Addition vom Compiler
eigentlich als zwei Schreibzugriffe umgesetzt wird. Kann er die Addition
mit 0 optimieren und durch einen Schreibzugriff ersetzen? Ich würd sagen
ja, da es "implementation defined" ist wie die Addition umgesetzt wird.
Auch bei
1
volatileinta;
2
volatileintb;
3
intc=a+b;
ist offen, ob der Zugriff auf a oder b zuerst durchgeführt wird. Auch
die eigentliche Addition muss nicht hier passieren. Nur die "side
effects", also das Lesen der Werte muss bis zum nächsten "sequence
point" (;) gelesen sein.
Volatile, Var kann sich seit dem letzten zugriff jederzeit geändert
haben. Verwende keinen Buffer (Register etc.), hole es IMMER aus der
originalen Quelle (Adresse etc.).
Wie das der jeweilige Compiler im einzelnen umsetzt/OPTIMIERT?-o
mh schrieb:> Rolf M. schrieb:>> Vielleicht>> kann die eigentliche Addtions-Instruktion weggelasen werden, aber eine>> Lese- und Schreibzugriff auf die Variable muss dennoch erfolgen.>> Es stellt sich aber die Frage, was passiert, wenn die eigentliche> Operation aus zwei Instruktionen besteht. Wenn die Addition vom Compiler> eigentlich als zwei Schreibzugriffe umgesetzt wird. Kann er die Addition> mit 0 optimieren und durch einen Schreibzugriff ersetzen? Ich würd sagen> ja, da es "implementation defined" ist wie die Addition umgesetzt wird.
Würde ich auch sagen. Ich würde es dennoch für sinnvoll erachten, immer
beide Schreibzugriffe zu machen.
> Auch bei> volatile int a;> volatile int b;> int c = a + b;> ist offen, ob der Zugriff auf a oder b zuerst durchgeführt wird.
Ja, das lässt C ja grundsätzlich offen.
> Auch die eigentliche Addition muss nicht hier passieren. Nur die "side> effects", also das Lesen der Werte muss bis zum nächsten "sequence> point" (;) gelesen sein.
Genau.
Arduino Fanboy D. schrieb:> Rolf M. schrieb:>> aber eine>> Lese- und Schreibzugriff auf die Variable muss dennoch erfolgen.> Interessante Sicht!
Der Zugriff wird ja sogar auch ohne die Addition durchgeführt.
Ein
1
PORTC=PORTC;
muss ja auch den Port lesen und den gelesenen Wert wieder zurück
schreiben. Ob man da jetzt noch 0 dazu addiert oder nicht, macht dafür
keinen Unterschied. Es gibt ja auch I/O-Register, bei denen so was
durchaus wichtig sein kann.
Selbst wenn man nur
1
PORTC;
schreibt, wird das zu einem Lesezugriff führen, denn der Ausdruck muss
evaluiert werden, auch wenn der Wert danach verworfen wird.
Rolf M. schrieb:> mh schrieb:>> Rolf M. schrieb:>>> Vielleicht>>> kann die eigentliche Addtions-Instruktion weggelasen werden, aber eine>>> Lese- und Schreibzugriff auf die Variable muss dennoch erfolgen.>>>> Es stellt sich aber die Frage, was passiert, wenn die eigentliche>> Operation aus zwei Instruktionen besteht. Wenn die Addition vom Compiler>> eigentlich als zwei Schreibzugriffe umgesetzt wird. Kann er die Addition>> mit 0 optimieren und durch einen Schreibzugriff ersetzen? Ich würd sagen>> ja, da es "implementation defined" ist wie die Addition umgesetzt wird.>> Würde ich auch sagen. Ich würde es dennoch für sinnvoll erachten, immer> beide Schreibzugriffe zu machen.
Halte ich auch für sinnvoll in diesem Fall. Aber wenn man volatile
benutzt, um Optimierungen zu verhindern, muss man hier evtl. erstmal im
Handbuch des Compilers suchen, ob er etwas dazu sagt.
> Selbst wenn man nur
1
PORTC;
> schreibt, wird das zu einem Lesezugriff führen, denn der Ausdruck muss> evaluiert werden, auch wenn der Wert danach verworfen wird.
Ja, das ist noch relativ einfach nachvollziehbar.
Aber dein
Rolf M. schrieb:> Ein
1
PORTC=PORTC;
> muss ja auch den Port lesen und den gelesenen Wert wieder zurück> schreiben.
ist da schon etwas schwieriger. Muss der "geänderte" Wert von PORTC am
Ende nochmal gelesen werden? Der Standard sagt:
1
An assignment operator stores a value in the object designated by the left operand. An
2
assignment expression has the value of the left operand after the assignment, but is not an
3
lvalue. The type of an assignment expression is the type of the left operand unless the
4
left operand has qualified type, in which case it is the unqualified version of the type of
5
the left operand. The side effect of updating the stored value of the left operand shall
6
occur between the previous and the next sequence point.
Der "has the value of the left operand after the assignment" Teil sagt
für mich JA!, aber den Standard verstehen ist schwer ...
mh schrieb:> Der "has the value of the left operand after the assignment" Teil sagt> für mich JA!, aber den Standard verstehen ist schwer ...
Hmm, du meinst, weil der "value" ja zur Ermittlung wieder gelesen werden
muss? Ich denke nicht dass das so gemeint ist, aber man könnte es
zugegebenermaßen so auslegen.
Rolf M. schrieb:> Hmm, du meinst, weil der "value" ja zur Ermittlung wieder gelesen werden> muss? Ich denke nicht dass das so gemeint ist, aber man könnte es> zugegebenermaßen so auslegen.
Wenn es nicht gemeint ist, hätte man nicht etwas wie "An assignment
expression has the value that is assigned to the left operand, but is
not an lvalue." schreiben können?
Sowohl gcc als auch clang lesen den Wert nach der Zuweisung nicht erneut
aus.
Also Folge sind
mh schrieb:> Der "has the value of the left operand after the assignment" Teil sagt> für mich JA!, aber den Standard verstehen ist schwer ...
Ich vermute die prähistorische Version des Standards (erkennt man leicht
an der verwendeten Terminologie), die du hast, enthält folgende
Anmerkung noch nicht:
1
The implementation is permitted to read the object to determine the value but is not required to, even when the object has volatile-qualified type.
Jemand schrieb:> Ich vermute die prähistorische Version des Standards (erkennt man leicht> an der verwendeten Terminologie), die du hast, enthält folgende> Anmerkung noch nicht:The implementation is permitted to read the object> to determine the value but is not required to, even when the object has> volatile-qualified type.
Ich hatte irgenwo ISO/IEC 9899/Cor3:2007 rumliegen. 13 Jahre würde ich
bei c jetzt nicht als prähistorisch ansehen. Man erkennt vllt. eine
dünne Staubschicht...
Sie bestätigen also meine Interpretation "read the object to determine
the value", zwingen aber niemanden es umzusetzen.