Forum: Compiler & IDEs ARM-GCC: Wert auslesen


von Walter Tarpan (Gast)


Lesenswert?

Hallo zusammen,
ich habe es mal wieder geschafft, mich in eine totale Anfängerfrage zu 
maneuvrieren:

Ich will ein Register auslesen, da dadurch das Statusflag zurückgesetzt 
wird. Den ausgelesenen Wert kann ich allerdings für nichts gebrauchen. 
Also mal schnell und naiv:
1
void dummy(void) {
2
  volatile temp; 
3
4
  // Auslesen, um Flag zu löschen
5
  temp = I2Cx->SR2; 
6
7
  // temp wird nicht weiter gebraucht und nicht weiter verwendet
8
}
Wie kann ich sicherstellen, daß diese Leseoperation nicht wegoptimiert 
wird. Immerhin kann der Compiler von ihrer Nebenwirkung ja nichts 
wissen?

Viele Grüße
W.T.

von Fred (Gast)


Lesenswert?

I2Cx muß volatile sein.

Wenn da ein Statusflag dahintersteht, ist es vermutlich schon so 
deklariert. Schau doch mal in den entsprechenden Systemheadern nach.

von Dr. Sommer (Gast)


Lesenswert?

Du brauchst nicht mal eine temporäre Variable. Einfach
1
I2Cx->SR2;
Sofern SR2 "volatile" ist...

von Hans (Gast)


Lesenswert?

Damit man beim späteren Lesen des Codes nicht über die Stelle stolpert, 
kann man es auch so schreiben:
1
(void) I2Cx->SR2;
Das verdeutlicht, dass der gelesene Wert nicht benötigt und deshalb 
verworfern wird. Ein erklärender Kommentar schadet an der Stelle 
natürlich auch nicht ...

von Simon H. (simi)


Lesenswert?

Hm... ist die Frage wirklich beantwortet?

Was bedeutet 'volatile'? m.W. dass der Compiler damit rechnen muss, dass 
sich der Wert einer Variable verändern kann, ohne dass er dies 
nachvollziehen kann. Und dass er somit keine Optimierungen vornehmen 
darf, die darauf beruhen, dass er den Wert einer Variable vermeintlich 
schon kennt.

Aber hilft das bei obigem Beispiel? Selbst wenn der Compiler weiss, dass 
er nicht weiss, was im SR2 Register steht, kann er doch, wenn obige 
Erklärung hinreichend ist, die Zeile dennoch wegoptimieren, denn das 
(wegen 'volatile' nicht vorhersehbara) Ergebnis wird nicht verwendet.

Ich hatte bisher nie das vom TO erwähnte Problem, darum habe ich mir das 
nie überlegt. Aber ich finde die Frage interessant. Bedeutet 'volatile' 
auch, dass ein Lesezugriff nicht nur ein für den Compiler nicht 
vorhersehbares Ergebnis liefern kann, sondern dass dieser Lesezugriff 
auch noch Randeffekte haben kann?

Oder anders gefragt: Was stimmt?

- Ein Lesezugriff auf eine Volatile-Variable darf nicht wegoptimiert 
werden
oder
- Ein Lesezugriff auf eine Volatile-Variable darf nicht wegoptimert 
werden, wenn das Ergebnis noch verwendet wird

: Bearbeitet durch User
von Fred (Gast)


Lesenswert?

Ersteres.

von Simon H. (simi)


Lesenswert?

Dann ist das zumindest auf Wikipedia falsch formuliert:

"In C und C++ wird durch diesen Typqualifikator spezifiziert, dass sich 
der Wert der Variable jederzeit ändern kann, beispielsweise durch andere 
Prozesse, Threads oder sogar externe Hardware[1]. Bei der Generierung 
des Maschinen-Codes aus einem in C oder C++ geschriebenen Programm 
verhindert die Kennzeichnung einer Variablen als volatile eine in diesem 
Fall die Funktionalität beeinträchtigende Optimierung, so dass das 
Programm immer auf den tatsächlich in der Hardware vorhandenen Wert 
zugreift.[2]"

Im ersten Satz fehlt somit: ... sowie dass ein Lesezugriff für den 
Compiler uneinsehbare Nebeneffekte haben kann... oder so.

Ich habe das aber nirgens je so gelesen... oder mich nicht geachtet...

: Bearbeitet durch User
von Rolf Magnus (Gast)


Lesenswert?

Fred schrieb:
> I2Cx muß volatile sein.

Genauer gesagt muß I2Cx ein Zeiger auf volatile sein. Der Zeiger selbst 
muß es aber nicht sein. Auch temp im Beispiel des Ursprungsposters muß 
nicht volatile sein. Wozu auch? Das stellt nur sicher, daß nach temp 
geschrieben wird, aber nicht, daß von I2Cx->SR2 gelesen wird.

Simon Huwyler schrieb:
> Hm... ist die Frage wirklich beantwortet?

Simon Huwyler schrieb:
> Was bedeutet 'volatile'? m.W. dass der Compiler damit rechnen muss, dass
> sich der Wert einer Variable verändern kann, ohne dass er dies
> nachvollziehen kann.

Oder auch umgekehrt, daß sie irgendeine Wirkung nach außen hat, die 
zwingend stattfinden muß.
Allgemeiner: Alle Lese- und Schreibzugriffe müssen so ausgeführt werden, 
wie sie im Code stehen.

von Simon H. (simi)


Lesenswert?

Rolf Magnus schrieb:
> Simon Huwyler schrieb:
>> Was bedeutet 'volatile'? m.W. dass der Compiler damit rechnen muss, dass
>> sich der Wert einer Variable verändern kann, ohne dass er dies
>> nachvollziehen kann.
>
> Oder auch umgekehrt, daß sie irgendeine Wirkung nach außen hat, die
> zwingend stattfinden muß.
> Allgemeiner: Alle Lese- und Schreibzugriffe müssen so ausgeführt werden,
> wie sie im Code stehen.

Sorry, dass ich hartnäckig bin, aber das finde ich jetzt wirklich 
interessant.

Aber Deine Erklärung oben reicht nicht. Was meinst Du mit "sie"? Der 
Wert der Variable? Ein Lesezugriff? Ist das so irgendwo definiert? 
Einfach allgemein zu sagen: Jeglicher Zugriff auf eine Volatile Variable 
darf nicht wegoptimiert werden, stimt m.E. nämlich auch nicht. Was, wenn 
der Zugriff in einer Funktion stattfindet, die definitiv nie aufgerufen 
wird? Ich denke, dann darf der Compiler das sehr wohl wegoptimeren.

Also z.B.

int x;
volatile int y;
if(0)
  x=y;

Ich glaube eher, der Compiler darf sehr wohl optimieren, aber er darf 
keine Schlüsse ziehen, die er glaubt ziehen zu können. Und da stellt 
sich mir eben die Frage: Was muss er alles für möglich halten?
Bis jetzt habe ich immer nur gelesen, dass der Compilder damit rechnen 
muss, dass sich der Wert der Variable verändert, und dass ein 
SCHREIBzugriff (genauer: eine Veränderung des Wertes dieser Variable; 
war das das 'sie' von Dir oben?)  etwas bewirken kann, das er nicht 
kennt.

Von Seiteneffekten eines LESEzugriffs habe ich nie irgendwas gesehen. 
Weiss da jemand eine Quelle, wo das steht?

: Bearbeitet durch User
von Rolf Magnus (Gast)


Lesenswert?

Simon Huwyler schrieb:
> Sorry, dass ich hartnäckig bin, aber das finde ich jetzt wirklich
> interessant.
>
> Aber Deine Erklärung oben reicht nicht. Was meinst Du mit "sie"? Ein
> Lesezugriff? Ist das so irgendwo definiert?

In der Definition der Sprache C:

********
An object that has volatile-qualified type may be modified in ways 
unknown to the implementation or have other unknown side effects. 
Therefore any
expression referring to such an object shall be evaluated strictly 
according to the rules of the abstract machine, as described in 5.1.2.3. 
Furthermore, at every sequence point the value last stored in the
object shall agree with that prescribed by the abstract machine, except 
as modified by the unknown factors mentioned previously.
********

Das Löschen des Flags durch lesen der Variable ist ein "other unknown 
side effect", wie Walter ja selbst schon selbst sehr treffend formuliert 
hat:

Walter Tarpan schrieb:
> Immerhin kann der Compiler von ihrer Nebenwirkung ja nichts
> wissen?

> Einfach allgemein zu sagen:
> Jeglicher Zugriff auf eine Volatile Variable darf nicht wegoptimiert
> werden, stimt m.E. nämlich auch nicht. Was, wenn der Zugriff in einer
> Funktion stattfindet, die definitiv nie aufgerufen wird? Ich denke, dann
> darf der Compiler das sehr wohl wegoptimeren.

Ich meinte schon Zugriffe, die überhaupt stattfinden können. Vielleicht 
war "so wie sie im Code steht" nicht ganz ideal. Vielleicht so: Alle 
Zugriffe, die beim Ablauf des Programms theoretisch ausgeführt werden 
müßten, dürfen von der Optimierung beliebig verändert werden, solange es 
keine volatile-Zugriffe sind. Die müssen alle durchgeführt werden, und 
sie müssen in der richtigen Reihenfolge durchgeführt werden.

von Simon H. (simi)


Lesenswert?

Also (folgende Codefragmente sind jetzt nicht unbedingt sinnvoll, aber 
ich will nur nochmal zeigen, was ich mine):

volatile int x = 0;
while(x!=0)
  doSomething();

Das darf er nicht wegoptimieren, weil er nicht weiss, ob x vielleicht 
doch plötzlich 1 werden könnte.

volatile int x = 0;
if(x==1)
{
  x = 0;
}

dito.

volatile int x = 0;
x=1;
x=2;

Das darf er nicht wegoptimieren, weil er nicht weiss, ob jemand anders 
davon beeinflusst wird, wenn der Wert auf 1 geht.

Aber im obigen Beispiel gilt nichts davon, WENN 'temp' nicht volatile 
gesetzt wird. Also:

int x;
volatile int y = 0;

x=y;

Darf er das nun wegoptimieren? Nach allen Erklärungen, die ich bis jetzt 
gesehen habe, schon. Denn:

Er darf NICHT einfach annehmen, dass y gleich 0 ist. ABER: Es ist ihm 
scheissegal, denn x wird später nie mehr verwendet, und das ist eben 
NICHT volatile.

Es sei denn, es ist explizit deklariert, dass der Compiler mit 
Nebeneffekten von LESEzugriffen auf Variablen rechnen muss. Ist es das?

EDIT:
Ok, habe gerade obige Antwort gesehen. Ich finde, das ist zumindest 
ziemlich vage formuliert. "other side effects"... aber ich lese die 
Quelle nochmals genau durch.

: Bearbeitet durch User
von Fred (Gast)


Lesenswert?

Ja.

von Simon H. (simi)


Lesenswert?

Dann halte ich aber die obige Deklaration für wirklich sehr sehr vage.

"An object that has volatile-qualified type may be modified in ways
unknown to the implementation or have other unknown side effects."

Was folgt, ist eine reine Schlussfolgerung:
"Therefore ..."

Was vesteht man unter "unknown side effects" eines Types? Wenn ich das 
so lese würde ich das verstehen als: Der INHALT kann Seiteneffekte 
haben. Also Die VERÄNDERUNG des Inthalts kann Seiteneffekte haben. Aber 
ein LESEZugriff finde ich, sollte da schon explizit erwähnt werden.

Mal ganz ganz ehrlich: Würdet Ihr aus obigem Satz (dem vor "therefore", 
der wie gesagt eine reine Schlussfolgerung ist) so verstehen, dass das 
LESEN, also das KOPIEREN eines Werts, auch einen Seiteneffekt haben 
könnte?

von Fred (Gast)


Lesenswert?

Lies doch einfach den Standard mal selbst.

von Rolf Magnus (Gast)


Lesenswert?

Es gibt noch eine Fußnote:

********
A volatile declaration may be used to describe an object corresponding 
to a memory-mapped input/output port or an object accessed by an 
asynchronously interrupting function. Actions on objects so declared 
shall not be ‘‘optimized out’’ by an implementation or reordered except 
as permitted by the rules for evaluating expressions.
********

Fußnoten sind allerdings meines Wissens nur erklärend und nicht 
normativ.


Simon Huwyler schrieb:
> Ich finde, das ist zumindest ziemlich vage formuliert. "other side
> effects"... aber ich lese die Quelle nochmals genau durch.

Naja, einen Satz hatte ich noch nicht mitzitiert:

********
What constitutes an access to an object that has volatile-qualified type 
is implementation-defined.
********

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Hier noch etwas mehr zu lesen von John Regehr:

"Nine ways to break your systems code using volatile"

http://blog.regehr.org/archives/28

von Simon H. (simi)


Lesenswert?

Rolf Magnus schrieb:
> ********
> What constitutes an access to an object that has volatile-qualified type
> is implementation-defined.
> ********

Ok. Das macht es klar. :-)

Wieder was gelernt! Aber der Wikpedia-Artikel muss definitiv 
überarbeitet werden. Denn die Erkärung da stimmt schlicht nicht.

"In C und C++ wird durch diesen Typqualifikator spezifiziert, dass sich 
der Wert der Variable jederzeit ändern kann, beispielsweise durch andere 
Prozesse, Threads oder sogar externe Hardware[1]"

Das ist, wie wenn ich schreiben würde: Ein Betriebssystem ist ein 
System, das Speicherzugriffe von Anwendungsprogrammen überwacht."

Stimmt schon. Aaaaaber da sind noch 'ne Menge andere Sachen. :-)

: Bearbeitet durch User
von Rolf Magnus (Gast)


Lesenswert?

Simon Huwyler schrieb:
> Was vesteht man unter "unknown side effects" eines Types?

Nicht eines Typs, sondern eine Objekts.

> Wenn ich das so lese würde ich das verstehen als: Der INHALT kann
> Seiteneffekte haben.

Ich lese es so, daß das Objekt selbst Seiteneffekte haben, also alles, 
was man damit machen kann (oder selbst wenn man nichts damit macht), 
kann Seiteneffekte produzieren. Genau deshalb darf kein einziger Zugriff 
wegoptimiert werden, da diese Seiteneffekte dem Compiler nicht bekannt 
sind und er deshalb nicht selbst sicherstellen kann, daß sie nicht 
verlorengehen. Genau dafür ist volatile da.

> Mal ganz ganz ehrlich: Würdet Ihr aus obigem Satz (dem vor "therefore",
> der wie gesagt eine reine Schlussfolgerung ist) so verstehen, dass das
> LESEN, also das KOPIEREN eines Werts, auch einen Seiteneffekt haben
> könnte?

Ich würde schlussfolgern, daß alles einen Seiteneffekt haben könnte. 
"other unknown side effects" heißt für mich "irgendwas beliebiges, von 
dem der Compiler nichts weiß". Darunter fällt der hier beschriebene 
Fall.

von Simon H. (simi)


Lesenswert?

Rolf Magnus schrieb:
> Ich lese es so, daß das Objekt selbst Seiteneffekte haben, also alles,
> was man damit machen kann (oder selbst wenn man nichts damit macht),
> kann Seiteneffekte produzieren. Genau deshalb darf kein einziger Zugriff
> wegoptimiert werden, da diese Seiteneffekte dem Compiler nicht bekannt
> sind und er deshalb nicht selbst sicherstellen kann, daß sie nicht
> verlorengehen. Genau dafür ist volatile da.

oooook..... hm.... klar. Nehmen wir mal etwas aus einer ganz anderen 
Ecke. Ein Copy Constructor oder Assignment Operator kann natürlich auch 
Seiteneffekte haben (wenn man gerne gefährlich lebt ;-) ). Insofern 
mache ich definitiv etwas mit einem Objekt, wenn ich es "nur" kopiere.

Jup. Macht Sinn. :-)

Aus dem verlinkten Text:
"For every read from a volatile variable by the abstract machine, the 
actual machine must load from the memory address corresponding to that 
variable.  Also, each read may return a different value"

Aus bisher jeder Erklärung von volatile (u.a. in Wikipedia) habe ich bis 
jetzt entnommen, dass der erste Satz (bloss) eine Folge des zweiten sei. 
Und das Wort "volatile" (flüchtig) deutet ja auch darauf hin.
Dieser Satz aber ist genial, denn er trifft es genau. Du MUSST jeden 
Read durchführen, und zwar NICHT bloss, weil das Ergebnis anders sein 
könnte, als Du meinst. Auch, wenn Dich das Ergebnis gar nicht 
interessiert.

Guter Text! Merci!

: Bearbeitet durch User
von Walter Tarpan (Gast)


Lesenswert?

Johann L. schrieb:
> Hier noch etwas mehr zu lesen von John Regehr:
>
> "Nine ways to break your systems code using volatile"
>
> http://blog.regehr.org/archives/28

Danke für die Antworten auf meine Frage. Und für den schönen Text.

von Walter Tarpan (Gast)


Lesenswert?

Genau in demselben Blog gibt es übrigens zu genau dieser Frage auch 
einen Artikel:

http://blog.regehr.org/archives/41

von Karl H. (kbuchegg)


Lesenswert?

Simon Huwyler schrieb:

> Du MUSST jeden
> Read durchführen, und zwar NICHT bloss, weil das Ergebnis anders sein
> könnte, als Du meinst. Auch, wenn Dich das Ergebnis gar nicht
> interessiert.

Genau das sagt der Standard
1
any expression referring to such an object shall be evaluated
2
strictly according to the rules of the abstract machine

Hinweis:
'shall' bedeutet in diesem Zusammenhang nicht: och mach das mal, wenn es 
dir Spass macht.
'shall' bedeutet: du hast das so zu tun!

'any expression', also jeglicher Ausdruck (in dem das volatile Objekt 
vorkommt), muss so ausgewertet werden, wie die Regeln der Sprache (und 
zwar die der abstrakten Maschine, also vor Optimierung) das 
vorschreiben.
1
   i;
ist ein Ausdruck. Wird dieser Ausdruck ausgewertet, dann erfolgt ein 
Lesezugriff auf i. In der abstrakten Maschine - vor der Optimierung. 
Wenn i volatile ist, dann muss hier ein Lesezugriff erfolgen, wenn die 
Programmausführung diesen Punkt erreicht.

In
1
  i + i;
erfolgen 2 Lesezugrgiff. Der Compiler darf das auch nicht zu
1
  2 * i;
oder
1
  i << 1;
oder gar
1
  i;
abkürzen.

Optimierungen sind nicht Teil der Sprache (mit einer Ausnahme in C++). 
Für Optimierungen gilt die 'as if' Regel als oberste Direktive, nach der 
sich das sichtbare Verhalten eines Programmes nicht von dem 
unterscheiden darf, was unoptimiert passieren würde. Unoptimiert muss 
ein Lesezugriff erfolgen, also muss er in diesem Fall auch in der 
optimierten Version erfolgen, weil ja de4r Compiler von 'unknown side 
effects' ausgehen muss.

: Bearbeitet durch User
von Rolf Magnus (Gast)


Lesenswert?

Karl Heinz schrieb:
> Für Optimierungen gilt die 'as if' Regel als oberste Direktive, nach der
> sich das sichtbare Verhalten eines Programmes nicht von dem
> unterscheiden darf, was unoptimiert passieren würde.

Wobei das "sichtbare Verhalten" laut Definiton aus zwei Dingen besteht, 
nämlich aus File-I/O und (man ahnt es schon) Zugriffen auf 
Volatile-Variblen.

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.