Forum: Compiler & IDEs Volatile-Zugriffe umsortieren


von Sven P. (Gast)


Lesenswert?

Hallo,

eigentlich eine ganz simple Sache:
1
volatile char buffer;
2
volatile char transmit;
3
4
irgendein_periodischer_interrupt {
5
  if (transmit) {
6
    mach_was(buffer);
7
    transmit = 0;
8
  }
9
}
10
11
/* irgendwo im Programm: */
12
buffer = 'X';
13
transmit = 1;

Insbesondere die letzten beiden Zeilen müssen in dieser Reihenfolge 
geschehen. Andernfalls könnte das transmit-Flag schon gesetzt werden, 
bevor der Puffer beschrieben wurde. Und natürlich würde der Interrupt 
genau dazwischen eintreten...

Beide Variablen sind als volatile gekennzeichnet. Aber bewirkt das 
(standardkonform), dass die beiden Zuweiseungen nicht umsortiert 
werden...?

Vielen Dank und Grüße,
Sven

von Peter II (Gast)


Lesenswert?

Sven P. schrieb:
> Beide Variablen sind als volatile gekennzeichnet. Aber bewirkt das
> (standardkonform), dass die beiden Zuweiseungen nicht umsortiert
> werden...?

ja

von Stefan E. (sternst)


Lesenswert?

Eine weitere Möglichkeit auf Nummer Sicher zu gehen wäre, aus den zwei 
Anweisungen eine zu machen, und mit einem Sequence-Point darin, der die 
Reihenfolge garantiert:
1
buffer = 'X' , transmit = 1;
IMO ist das so sogar besser lesbar, weil es die direkte 
Zusammengehörigkeit und Reihenfolgeabhängigkeit der beiden Zuweisungen 
dokumentiert.

von Sven P. (Gast)


Lesenswert?

Peter II schrieb:
> Sven P. schrieb:
>> Beide Variablen sind als volatile gekennzeichnet. Aber bewirkt das
>> (standardkonform), dass die beiden Zuweiseungen nicht umsortiert
>> werden...?
>
> ja

Und könntest du das auch bitte irgendwie, am besten anhand des 
C-Standards, belegen...? Das wäre super.

von Sven P. (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Eine weitere Möglichkeit auf Nummer Sicher zu gehen wäre, aus den zwei
> Anweisungen eine zu machen, und mit einem Sequence-Point darin, der die
> Reihenfolge garantiert:
>
1
buffer = 'X' , transmit = 1;
IMO ist das so sogar besser lesbar,
> weil es die direkte Zusammengehörigkeit und Reihenfolgeabhängigkeit der
> beiden Zuweisungen dokumentiert.

Naja, ob das lesbarer ist...
Schaden tut es nicht, aber der Sequence-Point ist auch schon vorhanden, 
wenn man es auf zwei Anweisungen verteilt.

Wie gesagt, ich spekuliere nun schon einige Stunden darüber herum und 
weiß trotzdem nicht so recht, wie ich die Spezifikationen im C-Standard 
auslegen soll. Drumherumfrickeln kann ich natürlich, im Zweifelsfall mit 
einer Speicherbarriere. Aber mich würd doch interessieren, was 
eigentlich der 'legale' Weg ist.

von (prx) A. K. (prx)


Lesenswert?

Sven P. schrieb:
> Und könntest du das auch bitte irgendwie, am besten anhand des
> C-Standards, belegen...? Das wäre super.

C99 6.7.3.6: 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.

von Sven P. (Gast)


Lesenswert?

Der Nachsatz hats gebracht. Jetzt kann ich ruhig schlafen :-)

von Markus F. (mfro)


Lesenswert?

Sven P. schrieb:
> Stefan Ernst schrieb:
>> Eine weitere Möglichkeit auf Nummer Sicher zu gehen wäre, aus den zwei
>> Anweisungen eine zu machen, und mit einem Sequence-Point darin, der die
>> Reihenfolge garantiert:
>>
1
buffer = 'X' , transmit = 1;
IMO ist das so sogar besser lesbar,
>> weil es die direkte Zusammengehörigkeit und Reihenfolgeabhängigkeit der
>> beiden Zuweisungen dokumentiert.
>

Das kann man zwar schreiben (auch weil es m.E. die Lesbarkeit erhöht), 
volatile deklarieren sollte/muß man die Variablen aber trotzdem.

Der Sequence-Point, der durch den Komma-Operator gesetzt wird, 
garantiert nur, daß alle Statements vor dem Komma abgeschlossen sind, 
bevor die nach dem Komma ausgeführt werden. Wenn der Compiler nicht 
"sieht" (über volatile), daß diese Statements in jedem Falle ausgeführt 
werden müssen, weil die Variablen potentiell außerhalb des Programmes 
verändert wurden bzw. die Zuweisung einen ihm unbekannten Seiteneffekt 
hat, darf er immer noch beschließen, die entsprechenden (aus seiner 
Sicht unnötigen) Statements komplett wegzuoptimieren.Im Beispiel: wenn 
der Compiler der Ansicht ist, daß buffer bereits den Wert 'X' hat, wird 
er den entsprechenden Code gar nicht generieren.

von Jürgen S. (starblue) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:
> Eine weitere Möglichkeit auf Nummer Sicher zu gehen wäre, aus den zwei
> Anweisungen eine zu machen, und mit einem Sequence-Point darin, der die
> Reihenfolge garantiert:
>
1
buffer = 'X' , transmit = 1;
> IMO ist das so sogar besser lesbar,
> weil es die direkte Zusammengehörigkeit und Reihenfolgeabhängigkeit der
> beiden Zuweisungen dokumentiert.

Das ist schlecht, weil kaum jemand die Feinheiten des Komma-Operators 
kennt.

Besser als zwei Anweisungen lassen und ggf. einen Kommentar schreiben.

von Charlie (Gast)


Lesenswert?

Sven P. schrieb:
> Drumherumfrickeln kann ich natürlich, im Zweifelsfall mit
>
> einer Speicherbarriere. Aber mich würd doch interessieren, was
>
> eigentlich der 'legale' Weg ist.

Das ist nicht "frickeln", sondern der einzig richtige und vernünftige 
Weg.

von Charlie (Gast)


Lesenswert?

Peter II schrieb:
> Sven P. schrieb:
>
>> Beide Variablen sind als volatile gekennzeichnet. Aber bewirkt das
>
>> (standardkonform), dass die beiden Zuweiseungen nicht umsortiert
>
>> werden...?
>
>
>
> ja

Falsch. volatile verhindert so erstmal kein Umsortieren.

von Sven P. (Gast)


Lesenswert?

Ich habe weitergelesen. Wenn ich das richtig interpretiere, was der 
Standard da formuliert, dann müsste das hier doch zu Problemem führen:
1
static u8 tx_buff[TX0_SIZE];
2
static u8 tx_in;
3
static u8 tx_out;
4
5
#define vu8(x)  (*(volatile u8*)&(x))
6
#define ROLLOVER( x, max )  x = ++x >= max ? 0 : x
7
          // count up and wrap around
8
9
ISR( USART0_UDRE_vect )
10
{
11
  if( tx_in == tx_out ){    // nothing to sent
12
    UTX0_IEN = 0;      // disable TX interrupt
13
    return;
14
  }
15
  UDR0 = tx_buff[tx_out];
16
  ROLLOVER( tx_out, TX0_SIZE );
17
}
18
19
void uputchar0( u8 c )
20
{
21
  u8 i = tx_in;
22
23
  ROLLOVER( i, TX0_SIZE );
24
/*1*/  tx_buff[tx_in] = c;
25
  while( i == vu8(tx_out));    // until at least one byte free
26
          // tx_out modified by interrupt !
27
  tx_in = i;
28
/*2*/  UTX0_IEN = 1;                         // enable TX interrupt
29
}
30
31
void uputs0_( u8 *s )
32
{
33
  while( *s )
34
    uputchar0( *s++ );
35
}

Es stammt auszugsweise aus Peter Danneggers USART-Ringpuffer. Die 
übrigen Definitionen finden sich im Header in Peters Archiv: 
Beitrag "AVR-GCC: UART mit FIFO"

In 'uputchar0' habe ich eine Zeile (1) markiert, in der in den 
Ringpuffer geschrieben wird. Der ist nicht als 'volatile' qualifiziert, 
genausowenig wie 'tx_in'. Es ist dem Compiler also m.M.n. erlaubt, die 
Zuweisungen herumzuschieben. Unter anderem dürfte er die auch erst nach 
der markierten Zeile (2) ausführen - das wäre entsprechend fatal.
Ein anderer Effekt würde sich zeigen, wenn 'uputchar0' gleich ganz als 
inline-Funktion umgesetzt wird, etwa in 'uputs0_'. Das darf der Compiler 
ja auch. Dann nämlich könnte er bis zum Ende der Schleife warten, bis 
tx_in wieder ins Ram geschrieben und damit für den Interrupt sichtbar 
wird. Dann würde der Interrupt garnicht merken, dass der Puffer sich 
füllt, also letztlich Deadlock.

M.M.n. müssten der Puffer und 'tx_in' wenigstens als 'volatile' 
qualifiziert sein. Oder alternativ müsste man vor dem Einschalten des 
Interrupts eine Memory Barrier einziehen.

Ich habe Peter bereits gefragt, ob er sich da mehr bei gedacht hat. Aber 
der antwortet nicht.

von Sven P. (Gast)


Lesenswert?

Charlie schrieb:
>> ja
>
> Falsch. volatile verhindert so erstmal kein Umsortieren.
Jetzt bin ich wieder verwirrt.

Das wäre ja dann höchst fatal!
Ich könnte ja nichtmal mehr die Peripherie des Mikroprozessors bedienen, 
wenn die Zugriffe eigentlich umsortiert werden können...

Vielleicht etwas präziser:
1
volatile int a;
2
int b;
3
volatile int c;
4
5
a = 1;
6
b = 2;
7
c = 3;
Wenn ich das strikt nach der oben zitierten Passage aus dem Standard 
interpretiere, habe ich mindestens drei Sequenzpunkte erzeugt, nämlich 
jeweils einen nach jeder der beiden Zuweisungen.
Der Standard sagt dann, dass der Wert, der auf das Objekt gespeichert 
ist, beim Sequenzpunkt mit der Vorstellung der 'abstrakten' Maschine 
übereinstimmt. Das müsste aber dann doch bedeuten, dass der Compiler im 
Beispiel hier zwar die Zuweisung an 'c' beliebig um die beiden anderen 
Zuweisungen verschieben darf. Aber die Abfolge der Zuweisungen an 'a' 
und 'b' muss gewahrt bleiben, d.h. 'b' darf seinen Wert nicht vor 'a' 
bekommen.

Oder...?

von Charlie (Gast)


Lesenswert?

Ja, wenn du einen Sequenzpunkt erzeugst. Das machst du aber zum Beispiel 
nicht bei reinem Lesen.

Ich will auch nur dem verbreiteten Irrglauben entgegentreten, volatile 
sei das Allheilmittel für Reordering und exklusiven Zugriff.

Aber das Forum erzieht die Leute ja so: volatile deklarieren und ISR und 
main können beide exklusiv zugreifen...

von Sven P. (Gast)


Lesenswert?

Charlie schrieb:
> Ja, wenn du einen Sequenzpunkt erzeugst. Das machst du aber zum Beispiel
> nicht bei reinem Lesen.
Hm. Eigentlich doch schon...?!
Der Standard sagt, ein Sequenzpunkt ist nach der expression in einem 
expression statement. Eine expression kann aber beispielsweise auch 
die conditional expression sein. Diese kann man bis zur /cast 
expression/ durchklopfen, die dann etwa sowas sein darf:
1
(void) REGISTER;
Das wäre also schon ein Sequenzpunkt. Denkfehler?

> Aber das Forum erzieht die Leute ja so: volatile deklarieren und ISR und
> main können beide exklusiv zugreifen...
Davon will ich mich distanzieren...

Was hälst du von der Geschichte mit dem UART-Puffer?

von Coder (Gast)


Lesenswert?

Über Code-reordering als fehlerquelle bin ich noch nie gestolpert. Denn 
die Ausführung wie oben hängt von zwei von einander abhängigen Variablen 
ab, die beide volatile sein sollten.

Bei nicht verschachtelten ISRs reichte ausserhalb des ISR-Contextes 
immer aus, den volatilen Zugriff mittels __disable_interrupt und 
__enable_interrupt einzurahmen.

von Sven P. (Gast)


Lesenswert?

Coder schrieb:
> Über Code-reordering als fehlerquelle bin ich noch nie gestolpert. Denn
> die Ausführung wie oben hängt von zwei von einander abhängigen Variablen
> ab, die beide volatile sein sollten.
In meinem Beispiel ja. Das kann ich auch anhand des Standards 
nachvollziehen.

Aber im UART-Puffer-Quelltext von Peter?
-> Beitrag "Re: Volatile-Zugriffe umsortieren"
Da macht es mir Sorgen...

von (prx) A. K. (prx)


Lesenswert?

Charlie schrieb:
> Falsch. volatile verhindert so erstmal kein Umsortieren.

Hättest du das etwas genauer?

von Coder (Gast)


Lesenswert?

IMHO würde ich die Variablen als volatile deklarierten und die Zugriffe 
so gestalten wie geschrieben. Auf einem AVR können 8-bit Zurgiffe atomic 
sein, da zum Speichern glaube ich nur eine instruktion nötig ist. Man 
bemerke dass er in der Schleife nicht ohne Grund einen volatile cast 
macht.

von Coder (Gast)


Lesenswert?

das löst aber nicht die reordering frage.

von Coder (Gast)


Lesenswert?

Mal ein Beispiel in den Raum werfen
1
volatile uint8_t FifoIndex;
2
volatile uint8_t b;
3
4
if (FifoIndex==10UL)
5
{
6
   b=12U;
7
}

Wäre hier Reordering möglich?

von (prx) A. K. (prx)


Lesenswert?

Charlie schrieb:
> Ja, wenn du einen Sequenzpunkt erzeugst. Das machst du aber zum Beispiel
> nicht bei reinem Lesen.

Volatile bezieht sich nicht nur auf Schreibzugriffe. Auch Lesezugriffe 
sind betroffen. Aber eben nur zwischen diversen volatile Zugriffen 
untereinander, nicht zwischen einem Mix von volatile und non-volatile.

von (prx) A. K. (prx)


Lesenswert?

Coder schrieb:
> Wäre hier Reordering möglich?

Nein. In if(a)b liegt zwischen a und b ein sequence point.

von Coder (Gast)


Lesenswert?

Mein obiges beispiel ist Müll. Sorry

Also ich habe struct
1
typedef struct
2
{
3
int16_t a;
4
int16_t b;
5
int16_t c;
6
} test_t
die ich so nutze
1
volatile test_t test.
2
3
test.a =10;
4
test.c =30;
5
test.b =20;

ich würde erwarten, dass der Compiler dies zu
1
test.a =10;
2
test.b =30;
3
test.c =20;
optimiert (reorder), da so der Zugriff in diesem Beispiel effektiver 
ist. Und er KANN es machen , weil die Variablen im Ergebnis bzw. 
Verwendung unabhängig von der Reihenfolge der Ausführung sind. Egal ob 
es volatile ist oder nicht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Coder schrieb:

> Wäre hier Reordering möglich?

Nein. Falls doch, ist es ein Compilerfehler wie etwa PR51374 im GCC:

http://gcc.gnu.org/PR51374

Wer einen avr-gcc 4.6.2 einsetzt, sollte das auch "live" nachvollziehen 
können :-)

von (prx) A. K. (prx)


Lesenswert?

Coder schrieb:
> ich würde erwarten, dass der Compiler dies zu [...]
> optimiert (reorder),

Ich nicht.

> Und er KANN es machen , weil die Variablen im Ergebnis bzw.
> Verwendung unabhängig von der Reihenfolge der Ausführung sind.

Nein. Er mag es vielleicht können, aber nicht dürfen.

Falls es dir um
  volatile struct { ... }
gegenüber
  struct { volatile ... }
geht: Das ist äquivalent.

Abgesehen davon sind
test.a =10;
test.c =30;
test.b =20;
und
test.a =10;
test.b =30;
test.c =20;
unabhängig von volatile im Ergebnis nicht identisch. Tippfehler?

von Coder (Gast)


Lesenswert?

Ja. Tippfehler. Bevor das jetzt hier ausartet, werde ich mir das 
gcc-manual durchlesen und die Suchmaschine benutzen. Verdammt, ich will 
das jetzt wissen...

von Sven P. (Gast)


Lesenswert?

Ich auch :-)

Also mit deiner Struktur kann ich weiterhelfen.
ISO/IEC8999:1999TC2 sagt in §6.5.2.3 Abs. 7: Wenn man eine Variable mit 
Strukturtyp als 'volatile' qualifiziert, schlägt die Qualifizierung 
quasi auf alle Elemente der Struktur durch.

Und die Zuweisungen an 'volatile'-qualifizierte Variablen dürfen nicht 
vertauscht werden, das hatten wir ja eingangs geklärt.

von (prx) A. K. (prx)


Lesenswert?

Coder schrieb:
> Bevor das jetzt hier ausartet, werde ich mir das
> gcc-manual durchlesen

Falsche Referenz. Die richtige wäre der C Standard.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. schrieb:
> Coder schrieb:
>> Bevor das jetzt hier ausartet, werde ich mir das
>> gcc-manual durchlesen
>
> Falsche Referenz. Die richtige wäre der C Standard.

Ist volatile nicht "Implementation defined"?

http://gcc.gnu.org/onlinedocs/gcc/Qualifiers-implementation.html

A. K. schrieb:
> Falls es dir um
>   volatile struct { ... }
> gegenüber
>   struct { volatile ... }
> geht: Das ist äquivalent.

Jein.  Wiederum ist das "Implementation defined".

Unterschiede wird man ja nach Target, dessen EABI und 
-fstrict-volatile-bitfields sehen.

http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fstrict_002dvolatile_002dbitfields-2342

von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:
>> geht: Das ist äquivalent.
>
> Jein.  Wiederum ist das "Implementation defined".

Ok, "äquivalent" mag übertrieben sein. Und volatile Bitfelder sind ein 
Thema für sich, auf die bezieht sich der Thread hier bisher nicht.

Wie Sven oben schon erwähnte erscheint mir §6.5.2.3.7 als ziemlich 
eindeutig und nicht "implementation defined".

von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:
> Ist volatile nicht "Implementation defined"?
> http://gcc.gnu.org/onlinedocs/gcc/Qualifiers-implementation.html

Dieser Abschnitt im GCC Manual und im Standard lässt nur die Frage 
offen, inwieweit Ausdrücke ohne Verwendung des Ergebnisses, wie eben
   *src;
einen Lesezugriff darstellen, oder bezogen auf das Ziel garnix.
Auch darum geht es im diesem Thread nicht.

In obigem
   transmit = 1;
ist der Sachverhalt wohl unstrittig.

Wahrscheinlich hat man vergessen, den Standard durch Patentanwälte 
korrekturlesen zu lassen. Und nun kommst du an, um durch dieses Nadelöhr 
ein Kamel zu schleusen. ;-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Hehe, ist bin bestimmt kein Advokat. Versprochen!

von Sven P. (Gast)


Lesenswert?

A. K. schrieb:
> Johann L. schrieb:
>> Ist volatile nicht "Implementation defined"?
>> http://gcc.gnu.org/onlinedocs/gcc/Qualifiers-implementation.html
>
> Dieser Abschnitt im GCC Manual und im Standard lässt nur die Frage
> offen, inwieweit Ausdrücke ohne Verwendung des Ergebnisses, wie eben
>    *src;
> einen Lesezugriff darstellen, oder bezogen auf das Ziel garnix.
> Auch darum geht es im diesem Thread nicht.
Auch das ist m.M.n. im Standard klar geregelt.
Schau mal im Anhang C: Dort stehen die Sequenzpunkte beschrieben.
Und dann schau im Anhang A.2 in die Grammatik. Dort kannst du vom 
'expression statement', welches ja einen Sequenzpunkt darstellt, bis 
hinauf zur 'primary expression' durchwandern, welche dann sowas wie 
'*src' ist.

Zumindest wenn 'src' volatile ist, sollte das eindeutig einen Zugriff 
bezeichnen, oder?

von (prx) A. K. (prx)


Lesenswert?

Sven P. schrieb:
> Zumindest wenn 'src' volatile ist, sollte das eindeutig einen Zugriff
> bezeichnen, oder?

Es geht um den Fall
   volatile int *src; *src;
Also um einen Zugriff auf "*src", nicht auf src.

Zumindest fanden es die Autoren von GCC nicht klar, ob das per Standard 
nun einen Zugriff darstellen soll, oder nicht.

von Peter D. (peda)


Lesenswert?

Sven P. schrieb:
> Ich habe Peter bereits gefragt, ob er sich da mehr bei gedacht hat.

Ich habe mit Keil C51 angefangen, da gab es kein Umsortieren. Ich weiß 
garnicht, ob der volatile überhaupt kennt.

Die ersten AVR-GCC haben auch wenig umsortiert oder wegoptimiert. Daß 
man volatile braucht, kam erst viel später. Es kann daher gut sein, daß 
in meinen älteren Beispielen mal ein volatile zu wenig ist.

Da ich gerne kleinen Code haben will, habe ich auch immer das 
unerwartete Inlinen abgeschaltet (ist default leider an). Somit werden 
auch kleine Funktionen aufgerufen und über Funktionsgrenzen darf ja 
nicht umsortiert werden.


Peter

von Sven P. (Gast)


Lesenswert?

A. K. schrieb:
> Sven P. schrieb:
>> Zumindest wenn 'src' volatile ist, sollte das eindeutig einen Zugriff
>> bezeichnen, oder?
>
> Es geht um den Fall
>    volatile int *src; *src;
> Also um einen Zugriff auf "*src", nicht auf src.
>
> Zumindest fanden es die Autoren von GCC nicht klar, ob das per Standard
> nun einen Zugriff darstellen soll, oder nicht.
Achso, nun hab ich das.
Das würde ja bedeuten, dass folgende drei Varianten jeweils semantisch 
verschieden sind?!
1
UDR;
2
3
(void) UDR;
4
5
char dummy;
6
dummy = UDR;
7
/* dummy wird ansonsten nicht mehr benutzt */

Ansonsten leuchtet die Syntax mir ja ein. Ich kann 'const int *' 
schreiben und dann ist das konstant, worauf der Zeiger zeigt. Oder aber 
int * const', dann kann ich den Zeiger nicht verschieben, aber dennoch 
die Daten verändern, auf die er zeigt. Über Sinn und Unsinn, den ein 
analoges Verhalten bei 'volatile' hätte, kann man freilich debattieren.


Peter Dannegger schrieb:
> über Funktionsgrenzen darf ja
> nicht umsortiert werden
Bist du da sicher? Funktionsgrenzen von Anwenderfunktionen gehören nicht 
zum 'observable behaviour', mit welchem der Standard argumentiert. Es 
spricht also eigentlich nichts dagegen, auch über die Funktionsgrenzen 
hinweg zu optimieren. Die meisten Compiler werden sicherlich spätestens 
dann aufgeben, wenn der Code in verschiedenen Objekten liegt, aber ob 
inline oder nicht, das sollte eigentlich keinen Einfluss auf das 
Verhalten des Programms haben...

Oh je. Was war das alles so einfach, als mir das alles noch egal war :-}

von Peter D. (peda)


Lesenswert?

Man merkt deutlich, daß C nicht für Echtzeitapplikationen gemacht wurde. 
In MC-Anwendungen kommt es aber oft darauf an, daß der Zeitpunkt und die 
Reihenfolge exakt eingehalten werden.

Das volatile finde ich auch eher als Krücke.
Es müßte einen Compilerschalter geben, mit dem man das Umsortieren 
verbieten kann. Oder zumindest ein Statement, wo man das für einen Block 
verbieten kann.


Peter

von Stefan W. (dl6dx)


Lesenswert?

Peter Dannegger schrieb:
> Ich habe mit Keil C51 angefangen, da gab es kein Umsortieren. Ich weiß
> garnicht, ob der volatile überhaupt kennt.

Anfang der 1990er hatte ich mit C51 (3.2x bis 3.40) gearbeitet. Hab 
gerade mal in die uralten Quelltexte geschaut: Es gibt ein paar als 
volatile definierte Variable, die sowohl aus dem normalen Programmfluss 
als auch aus einer ISR genutzt wurden.

Grüße

Stefan

von Sven P. (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Es müßte einen Compilerschalter geben, mit dem man das Umsortieren
> verbieten kann. Oder zumindest ein Statement, wo man das für einen Block
> verbieten kann.
Dann bist du aber schon ziemlich dicht dran, gleich einen Assembler zu 
benutzen...

von Stefan W. (dl6dx)


Lesenswert?

Peter Dannegger schrieb:
> Es müßte einen Compilerschalter geben, mit dem man das Umsortieren
> verbieten kann. Oder zumindest ein Statement, wo man das für einen Block
> verbieten kann.

Gibt es beim avr-gcc nicht ein Pragma, um eine "memory barrier" zu 
setzen?

Wenn ich das Konzept richtig verstanden habe, passiert da genau das, was 
du suchst.

Grüße

Stefan

von Andreas D. (rackandboneman)


Lesenswert?

http://stackoverflow.com/questions/2535148/volatile-qualifier-and-compiler-reorderings

Das bezieht sich zwar auf den C++-Standard ist aber voll von 
Formulierungen die einem helfen sollten die entsprechende Terminologie 
im C-Standard zu finden.

von Sven P. (Gast)


Lesenswert?

Stefan Wagner schrieb:
> Peter Dannegger schrieb:
>> Es müßte einen Compilerschalter geben, mit dem man das Umsortieren
>> verbieten kann. Oder zumindest ein Statement, wo man das für einen Block
>> verbieten kann.
>
> Gibt es beim avr-gcc nicht ein Pragma, um eine "memory barrier" zu
> setzen?
Im GCC reicht es, zu clobbern:
1
asm volatile("" ::: "memory");

Der GCC hat sicherlich auch builtins dafür (__sync_synchronize oder so).

von reading (Gast)


Lesenswert?

Sven P. schrieb:
> Oh je. Was war das alles so einfach, als mir das alles noch egal war :-}

Auf diesen Satz hast du Copyright! Der ist einmalig und kommt in meine 
Sprüche-Sammlung :-]

von Andreas D. (rackandboneman)


Lesenswert?

Warum wird hier eigentlich im gleichen Zusammenhang gesagt dass man den 
C-Standard und nicht die Implementierung zur Beantwortung heranziehen 
soll... und dann beschrieben wie man mit implementierungsabhängigen 
Mitteln das gewünschte erreicht :)

von Optimierer (Gast)


Lesenswert?

Optimierung mit -O2 enthält (u.a.)

-fschedule-insns  (Reorders instructions to minimize execution stalls)

Das reordering wird mit mehreren -fsched-... oder -fschedule-... options 
gesteuert. Welche könnte man verwenden?

von Coder (Gast)


Lesenswert?

Naja das war jetzt viel lärm um nicht so viel Meine Zusammenfassung ist, 
dass wenn man bei Compiler-Optmimierungen nicht erwarten kann, dass der 
Programmcode so ausgeführt wird, wie er als C Code geschrieben ist; 
Reordering hin oder her.

von Markus F. (mfro)


Lesenswert?

Peter Dannegger schrieb:
> Man merkt deutlich, daß C nicht für Echtzeitapplikationen gemacht wurde.
> In MC-Anwendungen kommt es aber oft darauf an, daß der Zeitpunkt und die
> Reihenfolge exakt eingehalten werden.
>
> Das volatile finde ich auch eher als Krücke.

Genau dafür ist es aber gedacht und macht auch genau das, was man will, 
wenn man's richtig anwendet. Irgendwie beginnt dieser Thread, sich 
langsam im Kreis zu drehen ;).

> Es müßte einen Compilerschalter geben, mit dem man das Umsortieren
> verbieten kann. Oder zumindest ein Statement, wo man das für einen Block
> verbieten kann.
>

Den gibt's. Zwar nicht im Standard, aber gcc tut meist das, was man 
erwartet: ohne Optimierung übersetzen.

Wenn >= gcc 4.4, kann man auch so was machen:
1
...
2
3
#pragma GCC push_options 
4
#pragma GCC optimize "O0"  /* oder "no-wasauchimmer" */
5
6
/* unoptimierter code */
7
...
8
#pragma GCC pop_options
9
10
/* Code wieder so optimiert wie in den Copmpileroptionen global gesetzt */
11
...

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.