Forum: Mikrocontroller und Digitale Elektronik static volatile variable in einer Funktion


von Alex (Gast)


Lesenswert?

Hallo,
1
static void init_uart(void)
2
{
3
static volatile baud_t baud;
4
...
5
setBaurate(baud);
6
}

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

von Einer K. (Gast)


Lesenswert?

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.

von Christian G (Gast)


Lesenswert?

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.

von mh (Gast)


Lesenswert?

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?

von Veit D. (devil-elec)


Lesenswert?

Alex schrieb:
> Hallo,
>
>
1
> static void init_uart(void)
2
> {
3
>   static volatile baud_t baud;
4
>   ...
5
>   setBaurate(baud);
6
> }
>

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

von Oliver S. (oliverso)


Lesenswert?

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

von Rolf M. (rmagnus)


Lesenswert?

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.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Ich sehe an dieser Stelle und mit diesem Codeschnipsel keine sinnvolle 
Verwendung von volatile.

von mh (Gast)


Lesenswert?

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.
noch einige Optimierungen offen lässt.

von Einer K. (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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
int i = 0;
2
volatile int j = 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.

von mh (Gast)


Lesenswert?

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
volatile int a;
2
volatile int b;
3
int c = 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.

von Einer K. (Gast)


Lesenswert?

Rolf M. schrieb:
> aber eine
> Lese- und Schreibzugriff auf die Variable muss dennoch erfolgen.
Interessante Sicht!

von Teo D. (teoderix)


Lesenswert?

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

von Rolf M. (rmagnus)


Lesenswert?

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.

von mh (Gast)


Lesenswert?

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

von Rolf M. (rmagnus)


Lesenswert?

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.

von mh (Gast)


Lesenswert?

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
1
a = b = c;
und
1
b = c;
2
a = b;
nicht identisch.

von Jemand (Gast)


Lesenswert?

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.

von mh (Gast)


Lesenswert?

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.

von Carl D. (jcw2)


Lesenswert?

Da hat "Alex" mal wieder alle nötigen Reizworte aufgereiht und kringelt 
sich nun.

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.