Discussion:
volatile und Zuweisungen
(zu alt für eine Antwort)
Thomas Richter
2015-08-16 14:42:52 UTC
Permalink
Raw Message
Hallo miteinander,

neulich bin ich über folgenden Code gestolpert:

struct Custom {....}; /* <-- irgendwelche Hardwareregister */

volatile struct Custom *custom = (volatile struct Custom *)...
/*irgendwelche Hardware addresse */

Jetzt greift der Code auf die Hardwareregister wie folgt zu:

custom->rega = custom->regb = 0x00;

Das interessante hierbei ist, dass die Hardwareregister nur
Schreibregister sind, und wenn man versucht, aus diesen Registern zu
lesen haben sie eine andere Funktion. Ist so unüblich nicht.

Ich hatte bislang den Eindruck, das Resultat des Zuweisungsoperators ist
die rechte Seite, also 0x00, womit obiges äquivalent zu

custom->rega = 0x00;
custom->regb = 0x00;

wäre, jedoch ohne eine Reihenfolge der Zuweisung zu definieren (kein
Sequenzpunkt).

Interessanterweise übersetzt der hier gebrauchte Compiler das ganze zu:

custom->regb = 0;
custom->rega = custom->regb;

und führt somit einen Lesevorgang aus, der natürlich Unfug erzeugt.
Interessanterweise *trotz* des "volatile"-Qualifiers.

Ich bin mir nicht ganz im Klaren, ob ein derartiger Compiler konform zum
C-Standard verhält. "volatile" sollte den Compiler eigentlich darauf
hinweisen, dass man auf die Elemente der Struktur nicht
nebenwirkungsfrei zugreifen kann, und das Ergebnis der Zuweisung ist ja
der rechte Operand, und nicht der Inhalt des linken. Trotzdem ensteht
"defekter Code".

Andererseits kann man sagen, dass der Effekt von "volatile"
implementierungsabhängig ist und vom Standard nicht genau definiert ist.
Das Compilermanual (ja, gibt es in der Tat, zwei dicke Binder) schweigt
sich leider zum Thema "volatile" aus.

Meinungen und Kommentare hierzu?
Bernd Nawothnig
2015-08-16 15:46:46 UTC
Permalink
Raw Message
Post by Thomas Richter
struct Custom {....}; /* <-- irgendwelche Hardwareregister */
volatile struct Custom *custom = (volatile struct Custom *)...
/*irgendwelche Hardware addresse */
custom->rega = custom->regb = 0x00;
Das interessante hierbei ist, dass die Hardwareregister nur
Schreibregister sind, und wenn man versucht, aus diesen Registern zu
lesen haben sie eine andere Funktion. Ist so unüblich nicht.
Ich hatte bislang den Eindruck, das Resultat des Zuweisungsoperators ist
die rechte Seite, also 0x00, womit obiges äquivalent zu
custom->rega = 0x00;
custom->regb = 0x00;
wäre, jedoch ohne eine Reihenfolge der Zuweisung zu definieren (kein
Sequenzpunkt).
custom->regb = 0;
custom->rega = custom->regb;
und führt somit einen Lesevorgang aus, der natürlich Unfug erzeugt.
Interessanterweise *trotz* des "volatile"-Qualifiers.
Der besagt ja auch nur, dass sich der Wert der Variablen ändern kann,
also etwa nicht in Registern zwischengespeichert werden darf. Ich
wette, diese Variante entsteht sogar nur, *weil* du volatile verwendet
hast, denn nun darf der Compiler gar nicht mehr die Konstante 0
verwenden, denn so hast Du es oben nicht hingeschrieben.

Von weiteren Nebenwirkungen weiß der Compiler nichts und muss das auch
gemäß Sprachspezifikation nicht wissen.
Post by Thomas Richter
Ich bin mir nicht ganz im Klaren, ob ein derartiger Compiler konform zum
C-Standard verhält. "volatile" sollte den Compiler eigentlich darauf
hinweisen, dass man auf die Elemente der Struktur nicht
nebenwirkungsfrei zugreifen kann,
Nein. Es heißt nur, dass der Wert der Variablen sich asynchron, also
von außen angestoßen, ändern kann. Von verbotenen Leseoperationen ist
dort keineswegs die Rede.
Post by Thomas Richter
und das Ergebnis der Zuweisung ist ja der rechte Operand, und nicht
der Inhalt des linken. Trotzdem ensteht "defekter Code".
Andererseits kann man sagen, dass der Effekt von "volatile"
implementierungsabhängig ist und vom Standard nicht genau definiert ist.
Das Compilermanual (ja, gibt es in der Tat, zwei dicke Binder) schweigt
sich leider zum Thema "volatile" aus.
Meinungen und Kommentare hierzu?
Guckst Du etwa hier:

http://www2.informatik.uni-halle.de/lehre/c/c_volat.html

Das Schlüsselwort volatile teilt dem Compiler mit, daß die mit name
bezeichnete Variable mit dem Datentyp typ durch Ereignisse außerhalb
der Kontrolle des Programms verändert werden kann.

Der Wert der Variablen muß deshalb vor jedem Zugriff neu aus dem
Hauptspeicher eingelesen werden, d.h. er darf nicht in einem Register
des Prozessors zwischengespeichert werden.

Der Compiler arbeitet bei mit volatile deklarierten Variablen ohne
jede Optimierung, d.h. läßt die entsprechenden Werte bei jedem Zugriff
neu aus dem Hauptspeicher laden und sorgt bei Veränderungen dafür, daß
die neuen Werte ohne Verzögerung dort sofort abgelegt werden.

Beispiel:

#include <time.h>

volatile time_t zeit;

volatile verhindert bestimmte Optimierungsmaßnahmen des Compilers,
es sorgt dafür, daß Operationen so ausgeführt werden, wie sie im
Quelltext notiert werden, d.h. zum Beispiel, es werden keine
Umstellungen vorgenommen und Werte werden nicht in einem Cache
gehalten, d.h. veränderte Werte werden nicht "zurückgehalten".





Bernd
--
no time toulouse
Thomas Richter
2015-08-16 17:06:50 UTC
Permalink
Raw Message
Post by Bernd Nawothnig
http://www2.informatik.uni-halle.de/lehre/c/c_volat.html
Das Schlüsselwort volatile teilt dem Compiler mit, daß die mit name
bezeichnete Variable mit dem Datentyp typ durch Ereignisse außerhalb
der Kontrolle des Programms verändert werden kann.
Eben. Und wenn ich

custom->rega = custom->regb = 0x00;

schreibe, und der C-Standard besagt, dass der Wert der Zuweisung

custom->regb = 0x00;

0x00 ist und nichts anderes, und sich der Wert von custom->regb
außerhalb der Kontrolle des C-Compilers ändern kann, so sehe ich
nicht, wie der Compiler hier auf die Idee kommt, Code zu generieren der
dieses Register liest. Das verändert nämlich dann den Wert der Zuweisung
auf einen nicht vom Compiler garantierten Wert, dessen Wert sollte aber
der Wert des Ausdrucks rechts vom Gleichheitszeichen, also x00, sein.
Post by Bernd Nawothnig
Der Wert der Variablen muß deshalb vor jedem Zugriff neu aus dem
Hauptspeicher eingelesen werden, d.h. er darf nicht in einem Register
des Prozessors zwischengespeichert werden.
Ja, aber wo ist in der Zeile

custom->rega = custom->regb = 0x00;

eine Lese-Operation? Die Zugriffe auf custom->regX erfolgen alle als
lvalue und nicht als rvalue. Man beachte die Assoziativität von "=",
d.h. obiges ist äquivalent zu

custom->rega = (custom->regb = 0x00);


Also, noch jemand mit einer Meinung hierzu?

Grüße,
Thomas
Bernd Nawothnig
2015-08-16 17:24:27 UTC
Permalink
Raw Message
Post by Thomas Richter
Post by Bernd Nawothnig
http://www2.informatik.uni-halle.de/lehre/c/c_volat.html
Das Schlüsselwort volatile teilt dem Compiler mit, daß die mit name
bezeichnete Variable mit dem Datentyp typ durch Ereignisse außerhalb
der Kontrolle des Programms verändert werden kann.
Eben. Und wenn ich
custom->rega = custom->regb = 0x00;
schreibe, und der C-Standard besagt, dass der Wert der Zuweisung
custom->regb = 0x00;
0x00 ist und nichts anderes, und sich der Wert von custom->regb
außerhalb der Kontrolle des C-Compilers ändern kann, so sehe ich
nicht, wie der Compiler hier auf die Idee kommt, Code zu generieren der
dieses Register liest. Das verändert nämlich dann den Wert der Zuweisung
auf einen nicht vom Compiler garantierten Wert, dessen Wert sollte aber
der Wert des Ausdrucks rechts vom Gleichheitszeichen, also x00, sein.
Post by Bernd Nawothnig
Der Wert der Variablen muß deshalb vor jedem Zugriff neu aus dem
Hauptspeicher eingelesen werden, d.h. er darf nicht in einem Register
des Prozessors zwischengespeichert werden.
Ja, aber wo ist in der Zeile
custom->rega = custom->regb = 0x00;
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Post by Thomas Richter
eine Lese-Operation? Die Zugriffe auf custom->regX erfolgen alle als
lvalue und nicht als rvalue.
Nein. Die Zuweisung selbst ist ein rvalue:

http://manderc.com/operators/assignoperator/

Der Zuweisungs-Operator erwartet links einen lvalue und rechts einen
rvalue und wird von rechts nach links abgearbeitet. Der Rückgabewert
ist in C ein rvalue: Der Wert des linken Operanden nach der Zuweisung.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^

Und das ist bei Dir custom->regb, weil erst custom->regb = 0x00
ausgewertet wird. Und der Wert dieser Zweisung ist eben nicht der der
rechte, sonder der linke Operand. Und das ist hier nun mal
custom->regb. Der Compiler könnte hier freilich optimieren, wenn Du
ihm das nicht mit volatile explizit verboten hättest. Nun *muss* er
custom->regb auslesen, denn es kann sich ja nach der Zuweisung von
außen verändert haben. Das schreibt die Sprachspezifikation bei
volatile nun mal so vor.
Post by Thomas Richter
Man beachte die Assoziativität von "=", d.h. obiges ist äquivalent zu
custom->rega = (custom->regb = 0x00);
Ganz genau. Und genau daraus ergibt sich das von Dir beobachtete
Verhalten.




Bernd
--
no time toulouse
Thomas Richter
2015-08-17 05:40:13 UTC
Permalink
Raw Message
Hi,
Post by Bernd Nawothnig
http://manderc.com/operators/assignoperator/
Der Zuweisungs-Operator erwartet links einen lvalue und rechts einen
rvalue und wird von rechts nach links abgearbeitet. Der Rückgabewert
ist in C ein rvalue: Der Wert des linken Operanden nach der Zuweisung.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^
Danke, das war der entscheidende Hinweis und mein Missverständnis.

Grüße,
Thomas
Florian Weimer
2015-08-16 17:51:41 UTC
Permalink
Raw Message
Post by Thomas Richter
custom->regb = 0;
custom->rega = custom->regb;
und führt somit einen Lesevorgang aus, der natürlich Unfug erzeugt.
Interessanterweise *trotz* des "volatile"-Qualifiers.
Das ist ein Compiler-Bug.
Post by Thomas Richter
Ich bin mir nicht ganz im Klaren, ob ein derartiger Compiler konform zum
C-Standard verhält. "volatile" sollte den Compiler eigentlich darauf
hinweisen, dass man auf die Elemente der Struktur nicht
nebenwirkungsfrei zugreifen kann, und das Ergebnis der Zuweisung ist ja
der rechte Operand, und nicht der Inhalt des linken.
Das ist falsch, es ist der Wert des linken Operands nach der Zuweisung
(6.5.16/3 in C99). Ich interpretiere den Standard aber so, daß kein
weiterer Zugriff auf das Objekt erfolgt (der Zugriff wäre nämlich
ungültig nach 6.5/2).
Bernd Nawothnig
2015-08-16 20:20:46 UTC
Permalink
Raw Message
Post by Florian Weimer
Post by Thomas Richter
custom->regb = 0;
custom->rega = custom->regb;
und führt somit einen Lesevorgang aus, der natürlich Unfug erzeugt.
Interessanterweise *trotz* des "volatile"-Qualifiers.
Das ist ein Compiler-Bug.
Das ist es mit Sicherheit nicht. Der Compiler macht hier nur genau
das, wozu er durch volatile gezwungen wird.
Post by Florian Weimer
Post by Thomas Richter
Ich bin mir nicht ganz im Klaren, ob ein derartiger Compiler konform zum
C-Standard verhält. "volatile" sollte den Compiler eigentlich darauf
hinweisen, dass man auf die Elemente der Struktur nicht
nebenwirkungsfrei zugreifen kann, und das Ergebnis der Zuweisung ist ja
der rechte Operand, und nicht der Inhalt des linken.
Das ist falsch, es ist der Wert des linken Operands nach der Zuweisung
(6.5.16/3 in C99).
Richtig. Und der linke Operand ist hier genau das, was sogar explizit
ausgelesen werden *muss*, wenn dieser Operand als volatile deklariert
wurde.
Post by Florian Weimer
Ich interpretiere den Standard aber so, daß kein weiterer Zugriff auf
das Objekt erfolgt (der Zugriff wäre nämlich ungültig nach 6.5/2).
Der erfolgt ja auch nicht. Aber wenn der Operand als volatile
deklariert wurde, darf der Compiler dieses explizite Auslesen nicht
wegoptimieren.

Interessant wäre es, was ohne das volatile herauskommt. Denn dann darf
er das Auslesen weglassen. Allerdings muss er es nicht.




Bernd
--
no time toulouse
Florian Weimer
2015-08-19 20:37:53 UTC
Permalink
Raw Message
Post by Bernd Nawothnig
Post by Florian Weimer
Post by Thomas Richter
custom->regb = 0;
custom->rega = custom->regb;
und führt somit einen Lesevorgang aus, der natürlich Unfug erzeugt.
Interessanterweise *trotz* des "volatile"-Qualifiers.
Das ist ein Compiler-Bug.
Das ist es mit Sicherheit nicht. Der Compiler macht hier nur genau
das, wozu er durch volatile gezwungen wird.
Das kann ich nicht glauben.

Hier ist ein weiteres Argument dafür, daß die mehrdeutige Formulierung
im Standard so auszulegen ist, wie ich meine.

Man betrachte diesen Beispielcode:

extern volatile int a;

void f(void)
{
a;
}

void g(void)
{
a = 1;
}

f liest offensichtlich aus a. Wegen volatile darf das nicht
wegoptimiert werden.

Nach Deiner Lesart des Standards schreibt g nach a *und* liest
anschließend aus a, weil wegen volatile der Lesezugriff ebenfalls
nicht wegoptimiert werden kann.
Helmut Schellong
2015-08-17 07:18:28 UTC
Permalink
Raw Message
Post by Florian Weimer
Post by Thomas Richter
custom->regb = 0;
custom->rega = custom->regb;
und führt somit einen Lesevorgang aus, der natürlich Unfug erzeugt.
Interessanterweise *trotz* des "volatile"-Qualifiers.
Das ist ein Compiler-Bug.
Das Wichtige ist, daß der Standard schreibt, der Wert und der
Typ eines Zuweisungsausdruckes kommt vom linken Operanden.
Insofern liegt kein Compiler-Bug vor.

Ich konstruiere Mehrfachzuweisungen so:
long=int=short=char= 123;
damit es z.B. kein Truncate gibt.
long=(int=(short=(char=123)));
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Stefan Reuther
2015-08-17 08:20:05 UTC
Permalink
Raw Message
Post by Florian Weimer
Post by Thomas Richter
Ich bin mir nicht ganz im Klaren, ob ein derartiger Compiler konform zum
C-Standard verhält. "volatile" sollte den Compiler eigentlich darauf
hinweisen, dass man auf die Elemente der Struktur nicht
nebenwirkungsfrei zugreifen kann, und das Ergebnis der Zuweisung ist ja
der rechte Operand, und nicht der Inhalt des linken.
Das ist falsch, es ist der Wert des linken Operands nach der Zuweisung
(6.5.16/3 in C99). Ich interpretiere den Standard aber so, daß kein
weiterer Zugriff auf das Objekt erfolgt (der Zugriff wäre nämlich
ungültig nach 6.5/2).
Ich interpretiere 6.5/2 als Anforderung an das Programm, nicht an das
Compilat.

Der Wert einer Zuweisung ist der Wert des linken Operanden nach der
Zuweisung. Den bekommt man halt sinnvoll am kleversten durch Auslesen
des linken Operanden, insbesondere, wenn dabei eine Konvertierung
beteiligt ist (double->float, double->int, etc.)


Stefan
Florian Weimer
2015-11-20 16:36:46 UTC
Permalink
Raw Message
Post by Florian Weimer
Post by Thomas Richter
custom->regb = 0;
custom->rega = custom->regb;
und führt somit einen Lesevorgang aus, der natürlich Unfug erzeugt.
Interessanterweise *trotz* des "volatile"-Qualifiers.
Das ist ein Compiler-Bug.
C11 stellt in einer Fußnote klar, daß das Verhalten unspezifiziert
ist, d.h. es kann ein Lesezugriff erfolgen, muß aber nicht, selbst bei
volatile.

Rainer Weikusat
2015-08-17 10:16:01 UTC
Permalink
Raw Message
Post by Thomas Richter
Hallo miteinander,
struct Custom {....}; /* <-- irgendwelche Hardwareregister */
volatile struct Custom *custom = (volatile struct Custom *)...
/*irgendwelche Hardware addresse */
custom->rega = custom->regb = 0x00;
Das interessante hierbei ist, dass die Hardwareregister nur
Schreibregister sind, und wenn man versucht, aus diesen Registern zu
lesen haben sie eine andere Funktion. Ist so unüblich nicht.
Ich hatte bislang den Eindruck, das Resultat des Zuweisungsoperators ist
die rechte Seite, also 0x00, womit obiges äquivalent zu
custom->rega = 0x00;
custom->regb = 0x00;
wäre, jedoch ohne eine Reihenfolge der Zuweisung zu definieren (kein
Sequenzpunkt).
custom->regb = 0;
custom->rega = custom->regb;
Mal unabhaengig von allen Norm-Ueberlegungen ist das exakt identisch mit

custom->rega = custom->regb = 0;

Man kann jetzt erwarten, dass ein optimierender Compiler erkennt, dass

custom->rega = 0;
custom->regb = 0;

dasselbe Result haben sollte aber einen Speicherzugriff weniger
benoetigt aber 'volatile' informiert den Compiler ausdruecklich, dass
Lesezugriffe als seiteneffektbehaftet gelten sollen dh wenn er sich
konform verhaelt, darf er eine solche Transformation dann nicht mehr
vornehmen, und muss es sowieso auf keinen Fall, dh der Code ist
unter allen Umstaenden falsch wenn custom->regb nicht gelesen werden
darf.
Bernd Nawothnig
2015-08-17 10:53:41 UTC
Permalink
Raw Message
Post by Rainer Weikusat
Mal unabhaengig von allen Norm-Ueberlegungen ist das exakt identisch mit
custom->rega = custom->regb = 0;
Man kann jetzt erwarten, dass ein optimierender Compiler erkennt, dass
custom->rega = 0;
custom->regb = 0;
dasselbe Result haben sollte aber einen Speicherzugriff weniger
benoetigt aber 'volatile' informiert den Compiler ausdruecklich, dass
Lesezugriffe als seiteneffektbehaftet gelten sollen
Wo steht das? volatile informiert den Compiler nur darüber, dass diese
Variable asynchron, also von außen verändert werden kann und darum vor
jeder Verwendung explizit ausgelesen werden muss und nicht etwa in
einem Register zur weiteren Verwendung gehalten werden darf. Von
möglichen Seiteneffekten dieses Lesens steht nichts im Standard.

Für diesen Sonderfall, dass ein Lesezugriff unerwünschte Seiteneffekte
hat und darum verboten sein sollte, müsste man sowas wie
write-only-Variablen einführen.




Bernd
--
no time toulouse
Ralf Damaschke
2015-08-18 18:40:11 UTC
Permalink
Raw Message
Post by Bernd Nawothnig
Post by Rainer Weikusat
benoetigt aber 'volatile' informiert den Compiler ausdruecklich, dass
Lesezugriffe als seiteneffektbehaftet gelten sollen
Wo steht das? volatile informiert den Compiler nur darüber, dass diese
Variable asynchron, also von außen verändert werden kann und darum vor
jeder Verwendung explizit ausgelesen werden muss und nicht etwa in
einem Register zur weiteren Verwendung gehalten werden darf. Von
möglichen Seiteneffekten dieses Lesens steht nichts im Standard.
Doch, die Nebeneffekte werden ausdrücklich erwähnt.
Siehe C99 5.1.2p2 und p3 (C11: p4).

Accessing a volatile object, [...] are all side effects, which are
changes in the state of the execution environment.

Und insbesondere:

An actual implementation need not evaluate part of an expression if it
can deduce that its value is not used and that no needed side effects
are produced (including any caused by calling a function or accessing a
volatile object).
Bernd Nawothnig
2015-08-18 22:13:40 UTC
Permalink
Raw Message
Post by Ralf Damaschke
Post by Bernd Nawothnig
Post by Rainer Weikusat
benoetigt aber 'volatile' informiert den Compiler ausdruecklich, dass
Lesezugriffe als seiteneffektbehaftet gelten sollen
Wo steht das? volatile informiert den Compiler nur darüber, dass diese
Variable asynchron, also von außen verändert werden kann und darum vor
jeder Verwendung explizit ausgelesen werden muss und nicht etwa in
einem Register zur weiteren Verwendung gehalten werden darf. Von
möglichen Seiteneffekten dieses Lesens steht nichts im Standard.
Doch, die Nebeneffekte werden ausdrücklich erwähnt.
Siehe C99 5.1.2p2 und p3 (C11: p4).
Accessing a volatile object, [...] are all side effects, which are
changes in the state of the execution environment.
An actual implementation need not evaluate part of an expression if it
can deduce that its value is not used and that no needed side effects
are produced (including any caused by calling a function or accessing a
volatile object).
Danke für die Richtigstellung. Aber damit wird der Zugriff - und um
den alleine ging es ja nur - keineswegs verboten, im Gegenteil, er
wird erzwungen:

This isn't exactly easy to interpret, but what it roughly means in
plain English is: since the access of volatile objects is a side
effect, the compiler is not allowed to optimize away such accesses,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
neither is it allowed to sequence them in a different order, which it
would otherwise perhaps do in order to get better performance on a CPU
with instruction cache/branch prediction, or just better performance
because it had certain values conveniently stored in some CPU register.




Bermd
--
no time toulouse
Stefan Reuther
2015-08-19 09:16:05 UTC
Permalink
Raw Message
Post by Bernd Nawothnig
Post by Ralf Damaschke
Doch, die Nebeneffekte werden ausdrücklich erwähnt.
Siehe C99 5.1.2p2 und p3 (C11: p4).
[Mein C99 hat kein 5.1.2p2?]
Post by Bernd Nawothnig
Post by Ralf Damaschke
Accessing a volatile object, [...] are all side effects, which are
changes in the state of the execution environment.
An actual implementation need not evaluate part of an expression if it
can deduce that its value is not used and that no needed side effects
are produced (including any caused by calling a function or accessing a
volatile object).
Danke für die Richtigstellung. Aber damit wird der Zugriff - und um
den alleine ging es ja nur - keineswegs verboten, im Gegenteil, er
This isn't exactly easy to interpret, but what it roughly means in
plain English is: since the access of volatile objects is a side
effect, the compiler is not allowed to optimize away such accesses,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Der Joker steht in C99 6.7.3p6: "What constitutes an access to an object
that has volatile-qualified type is implementation-defined."

Damit ist es dem Compiler überlassen, ob er für 'a = b = 0;' einen
Lesezugriff auf 'b' sieht oder nicht. Die meisten Compiler werden nur
insofern non-compliant sein, als dass sie nicht dokumentieren, wie sie
es zu tun gedenken :)


Stefan
Bernd Nawothnig
2015-08-19 11:48:50 UTC
Permalink
Raw Message
Post by Stefan Reuther
Post by Bernd Nawothnig
Post by Ralf Damaschke
Doch, die Nebeneffekte werden ausdrücklich erwähnt.
Siehe C99 5.1.2p2 und p3 (C11: p4).
[Mein C99 hat kein 5.1.2p2?]
Post by Bernd Nawothnig
Post by Ralf Damaschke
Accessing a volatile object, [...] are all side effects, which are
changes in the state of the execution environment.
An actual implementation need not evaluate part of an expression if it
can deduce that its value is not used and that no needed side effects
are produced (including any caused by calling a function or accessing a
volatile object).
Danke für die Richtigstellung. Aber damit wird der Zugriff - und um
den alleine ging es ja nur - keineswegs verboten, im Gegenteil, er
This isn't exactly easy to interpret, but what it roughly means in
plain English is: since the access of volatile objects is a side
effect, the compiler is not allowed to optimize away such accesses,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Der Joker steht in C99 6.7.3p6: "What constitutes an access to an object
that has volatile-qualified type is implementation-defined."
Damit ist es dem Compiler überlassen, ob er für 'a = b = 0;' einen
Lesezugriff auf 'b' sieht oder nicht. Die meisten Compiler werden nur
insofern non-compliant sein, als dass sie nicht dokumentieren, wie sie
es zu tun gedenken :)
Danke.

Wer mehr dazu lesen möchte:

https://www.gnu.org/software/autoconf/manual/autoconf-2.63/html_node/Volatile-Objects.html

Das alles ist in der Tat recht ernüchternd.





Bernd
--
no time toulouse
Florian Weimer
2015-08-20 05:22:59 UTC
Permalink
Raw Message
Post by Stefan Reuther
Der Joker steht in C99 6.7.3p6: "What constitutes an access to an object
that has volatile-qualified type is implementation-defined."
Bezieht sich das tatsächlich auf die Aktionen der abstrakten Maschine?
Oder nur auf die zusätzlichen, nicht im Standard spezifizierten
Aktionen (“ways unknown to the implementation”, selber Absatz)?
Stefan Reuther
2015-08-20 16:12:56 UTC
Permalink
Raw Message
Post by Florian Weimer
Post by Stefan Reuther
Der Joker steht in C99 6.7.3p6: "What constitutes an access to an object
that has volatile-qualified type is implementation-defined."
Bezieht sich das tatsächlich auf die Aktionen der abstrakten Maschine?
Oder nur auf die zusätzlichen, nicht im Standard spezifizierten
Aktionen (“ways unknown to the implementation”, selber Absatz)?
Davon gehe ich aus, denn diese Aktionen werden in dem Absatz auch
beschrieben ("the value last stored in the object shall agree with that
prescribed by the abstract machine"), und "access" wird über den ganzen
Standard-Text hinweg benutzt, um allerlei Zugriffe auf Objekte durch das
C-Programm / die abstrakte Maschine zu bezeichnen.


Stefan
Loading...