Forum: Compiler & IDEs ATMega - Volatile Funktionen im Interrupt OK?


von Stephan R. (stero)


Lesenswert?

Hallo Zusammen!

Ich möchte einen ATMega zum Ansteuern eines direkt daran angeschlossenen 
Motors verwenden. Dieser ATMega bekommt von einem anderen 
Mikrocontroller über die SPI Schnittstelle die Anweisung die Motor 
Drehrichtung zu setzen, oder Auskunft zu geben an den Mikrocontroller 
über die aktuelle Drehrichtung.

Um im Interrupt auf Variablen zuzugreifen müssen diese ja als Volatile 
deklariert werden. Wie ist das, wenn ich mit settern und gettern 
arbeiten möchte wie hier die beiden Funktionen in motor.h

Müssen die dann ebenfalls VOLATILE sein?

Sind Funktionsaufrufe im Interrupt grundsätzlich OK oder kann es 
Probleme geben, vielleicht wegen des Stacks?

Beste Grüße
Stephan



// ---------- motor.h --------------------

VOLATILE uint8_t get_motor_direction();
void set_motor_direction(VOLATILE uint8_t dir);



// ------------- motor.c ------------------

uint8_t motor_direction = 0;


volatile uint8_t get_motor_direction()
{
  return motor_direction;
}


void set_motor_direction(volatile uint8_t dir)
{
  motor_direction = dir;
}


// ------------ main.c ----------------------


ISR(SPI_STC_vect)
{
  uint8_t SPI_received_byte = SPDR;  // Zeichen von SPI einlesen

  switch (SPI_received_byte)
  {
    case 1 :
      do
      {
        SPDR = get_motor_direction();
      } while (SPSR & (1<<WCOL));
      break;

    case 2 :
      set_motor_direction(100);
  }
}

von ausfüllen (Gast)


Lesenswert?

Variablen die NUR im Interrupt verwendet werden müssen nicht als 
volatile deklariert werden.
Bei Variablen die im Interrupt und in der main verwendet werden muss der 
Zugriff atomar erfolgen und die Variablen als volatile gekennzeichnet 
werden.
Funktionsaufrufe im Interrupt sind grundsätzlich OK.

von Stephan R. (stero)


Lesenswert?

Hallo ausfüllen,

vielen Dank für deine hilfreiche Antwort!

Weiß vielleicht noch jemand, ob es erforlich ist die setter- und getter- 
Funktionen mit VOLATILE zu kennzeichnen?

von Karl H. (kbuchegg)


Lesenswert?

Stephan R. schrieb:

> Weiß vielleicht noch jemand, ob es erforlich ist die setter- und getter-
> Funktionen mit VOLATILE zu kennzeichnen?

Dir scheint nicht klar zu sein, worin die Bedeutung des Schlüsselwortes 
'volatile' liegt.

http://www.mikrocontroller.net/articles/FAQ#Was_hat_es_mit_volatile_auf_sich

Sobald dir das klar ist UND du verstanden hast, dass ein C Compiler 
nicht einfach mir nichts dir nichts Funktionsaufrufe wegoptimieren 
kann/darf sollte sich deine Frage ganz von alleine beantworten.

NB: Es gibt nicht mal eine Syntax, mit der man Funktionen als volatile 
markieren könnt.

von (prx) A. K. (prx)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Sobald dir das klar ist UND du verstanden hast, dass ein C Compiler
> nicht einfach mir nichts dir nichts Funktionsaufrufe wegoptimieren
> kann/darf

Wenn der Compiler den Inhalt einer Funktion kennt, oder sie als frei von 
Seiteneffekten deklariert ist (C++, in C evtl. nur bei gcc möglich), 
dann darf er. Funktionen sind Code wie jeder andere auch. Wenn er Code 
als überflüssig erkennt, kann er ihn wegoptimieren, auch wenn er durch 
einen Funktionaufruf eingerahmt ist.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:

> NB: Es gibt nicht mal eine Syntax, mit der man Funktionen als volatile
> markieren könnt.

Freilich geht das! Wir sind ja hier im GCC-Forum :-)
 
1
typedef void F (void);
2
3
volatile char x;
4
5
static void f (void)
6
{
7
    x++;
8
}
9
10
void bar (void)
11
{
12
    volatile F *vf = (volatile F*) f;
13
    vf();
14
    x++;
15
}

Allerdings will der TO die damit verbundene Semantik keinesfalls 
haben...

Ergo: Ein volatile zu viel kann echt übel sein.

von Oliver (Gast)


Lesenswert?

A. K. schrieb:
> Wenn der Compiler den Inhalt einer Funktion kennt, oder sie als frei von
> Seiteneffekten deklariert ist (C++, in C evtl. nur bei gcc möglich),
> dann darf er.

Das gilt aber nur für statische Funktionen.

Oliver

von Peter II (Gast)


Lesenswert?

ausfüllen schrieb:
> Funktionsaufrufe im Interrupt sind grundsätzlich OK.

aber langsam. Sobalt man eine Funktion in der Prozedur aufruft werden 
alle Register auf den Stack gesichter. Kosten zeit und speicher.

Wenn man schon mehre funktionsaufrufe hat, dann ist es egal ob man noch 
ein paar mein reinschriebt.

von Stephan R. (stero)


Lesenswert?

Karl Heinz Buchegger schrieb:
> NB: Es gibt nicht mal eine Syntax, mit der man Funktionen als volatile
> markieren könnt.

Wenn ich es auf den Punkt bringe ist meine Frage, ob man die folgenden 4 
zur Unterscheidung großgeschriebenen "VOLATILE" auch weglassen könnte, 
oder ob dann die volatile-Eigenschaft verloren geht. Der Compiler 
erzeugt zumindest gleichlangen Code im AVR Studio, wenn ich einen oder 
alle dieser 4 "VOLATILE" entferne und gibt keine Warnungen aus.

Weiß der Compiler also auch bei Weglassen der 4 "VOLATILE" nachher beim 
Funktionsaufruf in der ISR, dass der Zugriff auf die Variable volatile 
erfolgen soll?


_______________________________________________________________


// ---------- motor.h --------------------

VOLATILE uint8_t get_motor_direction();
void set_motor_direction(VOLATILE uint8_t dir);



// ------------- motor.c ------------------

volatile uint8_t motor_direction = 0;


VOLATILE uint8_t get_motor_direction()
{
  return motor_direction;
}


void set_motor_direction(VOLATILE uint8_t dir)
{
  motor_direction = dir;
}

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

volatile ist sinnvoll bei globale Variablen.

Keine der von dir markierten Stellen bezieht sich auf eine globale 
Variable.

Lass es einfach weg an den 4 genannten Stellen.

von Karl H. (kbuchegg)


Lesenswert?

A. K. schrieb:
> Karl Heinz Buchegger schrieb:
>> Sobald dir das klar ist UND du verstanden hast, dass ein C Compiler
>> nicht einfach mir nichts dir nichts Funktionsaufrufe wegoptimieren
>> kann/darf
>
> Wenn der Compiler den Inhalt einer Funktion kennt, oder sie als frei von
> Seiteneffekten deklariert ist (C++, in C evtl. nur bei gcc möglich),

Wie deklarierst du eine Funktion als 'frei von Seiteneffekten'?

Und gcc Erweiterungen lass ich da erst mal nicht zu. Reines ANSI-C

> dann darf er. Funktionen sind Code wie jeder andere auch. Wenn er Code
> als überflüssig erkennt, kann er ihn wegoptimieren, auch wenn er durch
> einen Funktionaufruf eingerahmt ist.

Aber erst mal muss er den Funktionskörper inlinen. Erst dann kann der 
Optimizer daran gehen und unnötigen Code eliminieren.
D.h. der Funktionsaufruf findet konzeptionell immer statt - selbst dann, 
wenn er durchs inlinen eben 'physisch' nicht mehr statt findet.

von Karl H. (kbuchegg)


Lesenswert?

Stephan R. schrieb:

> Weiß der Compiler also auch bei Weglassen der 4 "VOLATILE" nachher beim
> Funktionsaufruf in der ISR, dass der Zugriff auf die Variable volatile
> erfolgen soll?

Hast du den Link in die FAQ gelesen?

volatile ist der Hinweis an den Optimizer, dass er es bei Zugriff auf 
Variablen nicht übertreiben darf.
Wenn also überhaupt, dann macht es erst mal nur Sinn, sich den Kopf über 
die volatile Markierung von Variablen zu zerbrechen. Denn letzten Endes 
kommt es darauf an! Du willst in manchen Situationen einen garantierten 
Variablenzugriff erzwingen. Wo, in welcher Funktion der steht, ist 
völlig wurscht - du willst den Zugriff. Und wenn der Compiler die 
Funktion durch inlining auflöst, dann willst du immer noch den Zugriff 
erzwingen.

von (prx) A. K. (prx)


Lesenswert?

Oliver schrieb:
> Das gilt aber nur für statische Funktionen.

Nein. Es ist heute nicht selten, dass der einzelne Compilerlauf die 
Funktionen lediglich vorkompiliert und die Codeerzeugung im Linker 
erfolgt (link time code generation). Dort sind, was die Optimierung 
angeht, dann externe Funktionen mit statischen Funktionen ungefähr 
vergleichbar.

von (prx) A. K. (prx)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Aber erst mal muss er den Funktionskörper inlinen. Erst dann kann der
> Optimizer daran gehen und unnötigen Code eliminieren.
> D.h. der Funktionsaufruf findet konzeptionell immer statt - selbst dann,
> wenn er durchs inlinen eben 'physisch' nicht mehr statt findet.

Yep, und im Ergebnis verschwindet der Code dann u.U. ganz.

Das ist wie mit Variablen und ihre Zugriffe. Die verschwinden u.U. auch 
ganz, obwohl der Zugriff formal im Quellcode stattfindet, grad wie der 
Funktionsaufruf formal im Quellcode statfindet. Ohne volatile kann aber 
der Variablenzugriff genauso verschwinden wie der komplette Code eines 
Funktionsaufrufs.

von (prx) A. K. (prx)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Und gcc Erweiterungen lass ich da erst mal nicht zu. Reines ANSI-C

Was glaubst du wohl, warum ich "in C evtl. nur bei gcc möglich" 
reingeschrieben hatte? ;-)

von (prx) A. K. (prx)


Lesenswert?

Karl Heinz Buchegger schrieb:
> D.h. der Funktionsaufruf findet konzeptionell immer statt - selbst dann,
> wenn er durchs inlinen eben 'physisch' nicht mehr statt findet.

Der Unterschied liegt anderswo: Funktionen haben im Sprachkonzept von C 
keinen Zustand, der sich irgendwie ohne Kenntnis des Compilers ändern 
könnte - bei Variablen hingegen ist das prinzipiell möglich und 
vorgesehen (nicht nur bei volatile, auch Aliasing geht in diese 
Richtung).

Erst wenn man ein Szenario betrachtet, in dem der Code einer Funktion 
sich ohne Kenntnis des Compilers ad hoc ändern kann, wird volatile 
relevant. Sowas gibts natürlich, z.B. in Betriebssystemen, aber nicht 
direkt in C.

von Peter II (Gast)


Lesenswert?

Das Problem ist, das viele denken das volatile ändert irgendetwas im 
verhalten der ISR. Das ist aber nicht wirklich richtig. Der Code in der 
ISR ist auch ohne volatile korrekt und richtig. Ein Volatil erzeugt nur 
schlechtern Code und bringt hier eigentlich nur Nachteile.

Damit sollte auch klar sein, das eine volatile funktion in der ISR 
überhaupt keinen sinn macht.


Das Problem ist die Mainschleife, hier optimiert der compiler weil er 
nicht weiss das sich eine Variable ändert. Es reicht also vollkommen aus 
in der main auf die Variablen mit volatile zuzugreifen. (cast). Dieser 
code zieht zwar nicht schön aus, ist aber sogar effizenter.

Das ganze gilt nur unter der Bedingung das man in der ISR kein SEI 
aufruft.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> Es reicht also vollkommen aus
> in der main auf die Variablen mit volatile zuzugreifen. (cast). Dieser
> code zieht zwar nicht schön aus, ist aber sogar effizenter.

Hey, super Idee!

Scheint aber nicht zu funktionieren:
1
#include <stdint.h>
2
#include <avr/io.h>
3
4
volatile uint8_t    x;
5
6
int main ()
7
{
8
    while (1)
9
    {
10
        if (x)
11
        {
12
            PORTD = 0x01;
13
        }
14
    }
15
}

Übersetzt sich so:
1
00000048 <main>:
2
{
3
    while (1)
4
    {
5
        if (x)
6
        {
7
            PORTD = 0x01;
8
  48:  91 e0         ldi  r25, 0x01  ; 1
9
10
int main ()
11
{
12
    while (1)
13
    {
14
        if (x)
15
  4a:  80 91 60 00   lds  r24, 0x0060
16
  4e:  88 23         and  r24, r24
17
  50:  e1 f3         breq  .-8        ; 0x4a <main+0x2>
18
        {
19
            PORTD = 0x01;
20
  52:  92 bb         out  0x12, r25  ; 18
21
  54:  fa cf         rjmp  .-12       ; 0x4a <main+0x2>
22
23
00000056 <_exit>:
24
  56:  f8 94         cli
25
26
00000058 <__stop_program>:
27
  58:  ff cf         rjmp  .-2        ; 0x58 <__stop_program>

Hier ist die Welt noch in Ordnung: x wird immer neu gelesen.

Jetzt das Ganze mit Casting - so wie Du vorgeschlagen hast:
1
#include <stdint.h>
2
#include <avr/io.h>
3
4
uint8_t    x;
5
6
int main ()
7
{
8
    while (1)
9
    {
10
        if ((volatile) x)
11
        {
12
            PORTD = 0x01;
13
        }
14
    }
15
}

Ausgabe:
1
00000048 <main>:
2
3
int main ()
4
{
5
    while (1)
6
    {
7
        if ((volatile) x)
8
  48:  80 91 60 00   lds  r24, 0x0060
9
        {
10
            PORTD = 0x01;
11
  4c:  91 e0         ldi  r25, 0x01  ; 1
12
13
int main ()
14
{
15
    while (1)
16
    {
17
        if ((volatile) x)
18
  4e:  88 23         and  r24, r24
19
  50:  11 f0         breq  .+4        ; 0x56 <main+0xe>
20
        {
21
            PORTD = 0x01;
22
  52:  92 bb         out  0x12, r25  ; 18
23
  54:  fc cf         rjmp  .-8        ; 0x4e <main+0x6>
24
  56:  ff cf         rjmp  .-2        ; 0x56 <main+0xe>
25
26
00000058 <_exit>:
27
  58:  f8 94         cli
28
29
0000005a <__stop_program>:
30
  5a:  ff cf         rjmp  .-2        ; 0x5a <__stop_program>

Hier wird x NICHT neu gelesen, sondern lediglich auf das Register r24 
wiederholt zugegriffen.

Oder mache ich was falsch?

Gruß,

Frank

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Oder mache ich was falsch?

Ja.  Du kannst volatile nicht einfach so casten.  Was geht ist sowas:
1
#include <stdint.h>
2
#include <avr/io.h>
3
4
uint8_t    x;
5
6
int main ()
7
{
8
    while (1)
9
    {
10
        if (*(volatile uint8_t *)&x)
11
        {
12
            PORTD = 0x01;
13
        }
14
    }
15
}

Ergebnis:
1
.global main
2
        .type   main, @function
3
main:
4
/* prologue: function */
5
/* frame size = 0 */
6
/* stack size = 0 */
7
.L__stack_usage = 0
8
        ldi r24,lo8(1)
9
.L6:
10
        lds r25,x
11
        tst r25
12
        breq .L6
13
        out 50-32,r24
14
        rjmp .L6
15
        .size   main, .-main
16
        .comm x,1,1

von Peter II (Gast)


Lesenswert?

Frank M. schrieb:
> Hier wird x NICHT neu gelesen, sondern lediglich auf das Register r24
> wiederholt zugegriffen.

scheinbar lebt x nur im Register nicht im RAM damit ist das doch ok

lege mal ein ISR mit zugriff auf X an, dann sollte sie im RAM liegen.

Ich habe den cast so in der art gemacht

if ((volatile uint8_t)x)

von Peter II (Gast)


Lesenswert?

ja Jörg Wunsch hat den richtige Cast - wusste auch nicht mehr genau wie 
der aussah. Am besten in einem Makro verstecken.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Ja.  Du kannst volatile nicht einfach so casten.

So hatte ich Peter aber verstanden ;-)

> Was geht ist sowas:

>         if (*(volatile uint8_t *)&x)

Wunderbar, gerade selbst getestet - klappt!

Das erspart mir an vielen Stellen innerhalb von ISRs das Kopieren von 
volatile-Variablen in lokale Variablen, um den Zugriff zu optimieren.

Tatsächlich muss man lediglich ausserhalb der ISR "suboptimieren" ;-)

Gruß und Dank,

Frank

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> Am besten in einem Makro verstecken.

Du meinst, sowas hier? ;-)
1
#include <stdint.h>
2
#include <avr/io.h>
3
4
uint8_t    x;
5
6
#define MAKEVOLATILE(x) (*(volatile typeof(x) *)&(x))
7
8
int main ()
9
{
10
    while (1)
11
    {
12
        if (MAKEVOLATILE(x))
13
        {
14
            PORTD = 0x01;
15
        }
16
    }
17
}

von Peter II (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Du meinst, sowas hier? ;-)

ja danke, ganz vergessen das so soetwas wie typeof in C ja auch gibt.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Du meinst, sowas hier? ;-)
>
1
> #define MAKEVOLATILE(x) (*(volatile typeof(x) *)&(x))
2
>

Sehr schön, nur "x" ist hier speziell als Makro-Argument verwirrend, 
weil die Variable x den gleichen Namen hat. Besser also:
1
#define MAKEVOLATILE(var) (*(volatile typeof(var) *)&(var))

von Peter II (Gast)


Lesenswert?

jetzt stellt sich aber noch die Frage was bei
1
if ( MAKEVOLATILE(x) == 1 ) {
2
   x++
3
}

passiert. kann es passierne das die änderung an X noch nicht im Ram 
landen?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> jetzt stellt sich aber noch die Frage was bei
>
>
1
> if ( MAKEVOLATILE(x) == 1 ) {
2
>    x++
3
> }
4
>
>
> passiert. kann es passierne das die änderung an X noch nicht im Ram
> landen?

Scheint zu klappen:
1
00000048 <main>:
2
3
int main ()
4
{
5
    while (1)
6
    {
7
        if (MAKEVOLATILE(x))
8
  48:  80 91 60 00   lds  r24, 0x0060
9
  4c:  88 23         and  r24, r24
10
  4e:  e1 f3         breq  .-8        ; 0x48 <main>
11
        {
12
            x++;
13
  50:  80 91 60 00   lds  r24, 0x0060
14
  54:  8f 5f         subi  r24, 0xFF  ; 255
15
  56:  80 93 60 00   sts  0x0060, r24
16
  5a:  f6 cf         rjmp  .-20       ; 0x48 <main>
17
18
0000005c <_exit>:
19
  5c:  f8 94         cli
20
21
0000005e <__stop_program>:
22
  5e:  ff cf         rjmp  .-2        ; 0x5e <__stop_program>

Der Wert von x wird im Ram zurückgespeichert. Aber ob man sich darauf 
verlassen kann?

von Stephan R. (stero)


Lesenswert?

Jörg Wunsch schrieb:
> #define MAKEVOLATILE(x) (*(volatile typeof(x) *)&(x))

Ich freue mich sehr über die vielen kompetenten Antworten und Ideen. 
Danke!
Grüße, Stephan

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Frank M. schrieb:

> Der Wert von x wird im Ram zurückgespeichert. Aber ob man sich darauf
> verlassen kann?

Der x++-Zugriff ist nicht volatile und das alles hat zudem das Problem, 
daß es nicht atomar ist.

Und m.E. sind solche Casts purer Hack den man vermeiden sollte.

Für jede Formulierung mit diesem Hack gibt es auch eine saubere 
Formulierung ohne.

von Coder (Gast)


Lesenswert?

Eine Variable, die an sich nicht volatile ist, an gewissen Stellen per 
cast volatile zu machen, ist nicht die feine Art. Das habe ich so noch 
nicht gesehen.

Manchmal ist man halt der Gnade des Compilers ausgeliefert oder man hat 
irgend etwas falsch gemacht.

von Peter II (Gast)


Lesenswert?

Coder schrieb:
> Eine Variable, die an sich nicht volatile ist, an gewissen Stellen per
> cast volatile zu machen, ist nicht die feine Art. Das habe ich so noch
> nicht gesehen.

das liegt aber nur daran das es nichts besseres in C gibt. Und speziell 
auf dem AVRs wo man schon ein wenig auf CPU leistung achten sollte finde 
ich diese sehr sinnvoll.

Warum alle zugriffe auf eine Variabel volatile machen und damit 
wesentlich schlechteren code erzeugen, wenn du eine davon stelle davon 
ausreichen würde. Das Kopieren in Temp variabel ist doch auch nur eine 
krücke.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Der x++-Zugriff ist nicht volatile und das alles hat zudem das Problem,
> daß es nicht atomar ist.

Das ist mir klar. Er ist aber auch nicht atomar, wenn man die Variable 
von vornherein als volatile definiert.

> Und m.E. sind solche Casts purer Hack den man vermeiden sollte.

Also doch lieber volatile-Variablen auch volatile definieren und in der 
ISR dann die volatile-Variable, die u.U. mehrfach in dieser ISR benötigt 
werden, in eine lokale Variable kopieren (und gegegebenenfalls am Ende 
zurückkopieren) - so wie es überall gepredigt wird?

von Karlo (Gast)


Lesenswert?

Ich finde diese Tatsache auch sehr interessant. Hab bisher auch 
Variablen als volatile markiert (ohne gezielten Cast) weil ich nicht 
wusste dass eine ISR eine Variable immer neu lädt und schreibt.

Kann man das Makro denn noch erweitern, um den Zugriff in der Main 
atomar durchzuführen?

Da (zumindest beim AVR) im normalfall eine ISR nicht durch eine weitere 
unterbrochen wird wäre der Zugriff in der ISR automatisch atomar und 
müsste nur in der main gezielt "atomar gecastet" werden.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Johann L. schrieb:

>> Und m.E. sind solche Casts purer Hack den man vermeiden sollte.
>
> Also doch lieber volatile-Variablen auch volatile definieren und in der
> ISR dann die volatile-Variable, die u.U. mehrfach in dieser ISR benötigt
> werden, in eine lokale Variable kopieren (und gegegebenenfalls am Ende
> zurückkopieren) - so wie es überall gepredigt wird?

Ja; zumindest ist das mein Favorit.  Der Code wird dadurch u.U. sogar 
besser als mir dem volatile-Cast, etwa wenn Aliasing ins Spiel kommt.

Zudem wird der volatile-Cast noch hässlicher, wenn man mit Zeigern 
hantiert, über die auf die Variable(n) zugegriffen wird.

von Falk B. (falk)


Lesenswert?

@  Peter II (Gast)

>> Eine Variable, die an sich nicht volatile ist, an gewissen Stellen per
>> cast volatile zu machen, ist nicht die feine Art. Das habe ich so noch
>> nicht gesehen.

Ist auch Schrott.

>das liegt aber nur daran das es nichts besseres in C gibt.

Doch. Mach es einfach wie der Rest der Welt. Die Variable als volatile 
deklarieren.

> Und speziell
>auf dem AVRs wo man schon ein wenig auf CPU leistung achten sollte finde
>ich diese sehr sinnvoll.

Keine Sekunde.

>Warum alle zugriffe auf eine Variabel volatile machen und damit
>wesentlich schlechteren code erzeugen,

Unsinn.

> wenn du eine davon stelle davon
>ausreichen würde.

Unsinn die 2. Denn dann kann an einigen Stellen lokal optimiert werden 
und nichtvolatile zugegriffen werden, und dein "Konzept" geht baden. Nur 
weil es manchmal funktioniert, ist es noch lange nicht richtig.

>Das Kopieren in Temp variabel ist doch auch nur eine
>krücke.

Nö, das ist solide. Und gängige Praxis.
Wenn man die Grundlagen beim Thema Interrupt verstanden hat, löst 
sich dieses "Problem" in Luft auf. Dann hat man nämlich ein Minimum an 
Variablen, welche zwischen ISR und main kommunizieren und gut. Und das 
"verschwendet" auch keine CPU-Leistung sondern ist schlicht notwendig. 
Und bei dem richtigen Konzept auch kein Thema.

Denn HIER liegt das eigentliche Problem des OP. Sein Konzept mit den 
Funktionen in der ISR und der SPI-Datenaufnahme und Verarbeitung ist 
schlecht.

MfG
Falk

von Falk B. (falk)


Lesenswert?

@  Karlo (Gast)

>Ich finde diese Tatsache auch sehr interessant. Hab bisher auch
>Variablen als volatile markiert (ohne gezielten Cast) weil ich nicht
>wusste dass eine ISR eine Variable immer neu lädt und schreibt.

Das tut sie NICHT!

von Peter II (Gast)


Lesenswert?

Falk Brunner schrieb:
> Das tut sie NICHT!

klar tut sie das immer. eine ISR kann sich nichts in Registern merken.


> >auf dem AVRs wo man schon ein wenig auf CPU leistung achten sollte finde
> >ich diese sehr sinnvoll.
>
> Keine Sekunde.

ohne tmp Variabel auf jeden Fall.

volatile uint8_t x;

if ( x == 12 ) { ... }
if ( x == 14 ) { ... }
if ( x == 18 ) { ... }
if ( x == 20 ) { ... }

das ist viel weniger code ohne volatile, und damit auch schneller. Klar 
ein Temp variable hilft hier. Aber ohne volatile spare ich mir die tmp 
variable.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> Falk Brunner schrieb:
>> Das tut sie NICHT!
>
> klar tut sie das immer. eine ISR kann sich nichts in Registern merken.

Natürlich kann sie das. Falks Antwort bezog sich auf beliebige 
Variablen, nicht speziell auf volatiles.

von Peter II (Gast)


Lesenswert?

Frank M. schrieb:
> Peter II schrieb:
>> Falk Brunner schrieb:
>>> Das tut sie NICHT!
>>
>> klar tut sie das immer. eine ISR kann sich nichts in Registern merken.
>
> Natürlich kann sie das. Falks Antwort bezog sich auf beliebige
> Variablen, nicht speziell auf volatiles.

Noch mal:

Eine ISR kann sich "außerhalb" ihres aufrufes nichts in Register merken. 
Egal welche art von Variablen. Die ISR muss jeden Variabel aus dem Ram 
laden und damit auch am ende wieder in den Ram schreiben, wenn sie die 
variabel geändert hat.

von Stephan R. (stero)


Lesenswert?

Falk Brunner schrieb:
> Denn HIER liegt das eigentliche Problem des OP. Sein Konzept mit den
> Funktionen in der ISR und der SPI-Datenaufnahme und Verarbeitung ist
> schlecht.

Ich habe bisher im Interrupt nur die SPI-Daten angenommen und dann wie 
du vorschlägst für das Hauptprogramm ein Flag gesetzt, das die 
empfangenen Daten auswertet.

Bei SPI Kommunikation ist es nun so, dass ich den uC für den Motor als 
SPI Slave betreibe. Dann kann er selber die Daten nicht aktiv 
verschicken sondern muß sehr schnell die Daten bereitstellen, so dass 
der Master mit seiner Clock Leitung die Daten "heraustakten" kann. Eine 
zusätzliche Interruptleitung zwischen SPI Master und dem 
"Motor-Slave-uC" gibt es nicht, daher wartet der Master einige uSec bis 
er die Daten vom Slave heraustaktet. Wenn der Slave die Daten nicht 
rechtzeitig bereitstellt merkt der Master gar nicht, dass er nur Müll 
empfangen hat. Um das zu verhindern will ich sofort im Interrupt 
antworten.

Einzige Alternative die ich sehe wäre noch den Slave auf Master 
umzuschalten und die Daten aktiv zu senden. Ich bin mir noch nicht 
sicher ob das eine gute Idee ist, weil noch mehr Slaves an der SPI 
Schnittstele hängen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> Noch mal:
>
> Eine ISR kann sich "außerhalb" ihres aufrufes nichts in Register merken.
> Egal welche art von Variablen. Die ISR muss jeden Variabel aus dem Ram
> laden und damit auch am ende wieder in den Ram schreiben, wenn sie die
> variabel geändert hat.

Das ist natürlich selbstverständlich, das kann auch keine andere 
stinknormale Funktion in C.

Karlo schrieb aber was anderes:

>Ich finde diese Tatsache auch sehr interessant. Hab bisher auch
>Variablen als volatile markiert (ohne gezielten Cast) weil ich nicht
>wusste dass eine ISR eine Variable immer neu lädt und schreibt.

Das liest sich so, als ob speziell in ISRs Variablen vom Compiler 
prinzipiell wie volatiles behandelt werden würden:

       "immer neu lädt und schreibt"
        ^^^^^
        (also bei jedem Zugriff)

Diese generelle Aussage stimmt so nicht.

von (prx) A. K. (prx)


Lesenswert?

Peter II schrieb:
> ja danke, ganz vergessen das so soetwas wie typeof in C ja auch gibt.

In Standard-C gibts das auch nicht. Aber in GCC.

von Peter II (Gast)


Lesenswert?

Frank M. schrieb:
> Das ist natürlich selbstverständlich, das kann auch keine andere
> stinknormale Funktion in C.

main ist auch eine normale funktion - aber diese wird halt nicht 
verlassen. Damit kann sich der compieler die Freiheit nehmen variablen 
in Registern vorzuhalten, das ganze betrifft dann auch unterfunktionen 
von main, denn hier kann er sie inlinen und damit auch den zugriff auf 
den Ram sparen.

von Falk B. (falk)


Lesenswert?

@  Peter II (Gast)

>Eine ISR kann sich "außerhalb" ihres aufrufes nichts in Register merken.
>Egal welche art von Variablen.

Falsch. Lokale Variablen, welche static sind ;-)

von Peter II (Gast)


Lesenswert?

Falk Brunner schrieb:
> Falsch. Lokale Variablen, welche static sind ;-)

wie soll ich das nun wieder verstehen? Dir ist doch bestimmt klar das 
sie auch nur im Ram liegen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter II schrieb:
> volatile uint8_t x;
>
> if ( x == 12 ) { ... }
> if ( x == 14 ) { ... }
> if ( x == 18 ) { ... }
> if ( x == 20 ) { ... }
>
> das ist viel weniger code ohne volatile, und damit auch schneller. Klar
> ein Temp variable hilft hier. Aber ohne volatile spare ich mir die tmp
> variable.

Das spart dir noch viel mehr Quellcode:
1
if(x==12){...}if(x==14){...}if(x==18){...}if(x==20){...}
Wozu das ganze Leerzeichen-Geraffel???
Kost nur Zeit beim Tippen!

von Peter II (Gast)


Lesenswert?

Johann L. schrieb:
> Wozu das ganze Leerzeichen-Geraffel???
> Kost nur Zeit beim Tippen!

Sache die nur einmal gemacht werden( tippen) müssen nicht schnell gehen, 
bei dingen die sicher oft wiederholen (ausführung) sollte man schon 
darauf achten.

von Falk B. (falk)


Lesenswert?

@  Stephan R. (stero)

>Ich habe bisher im Interrupt nur die SPI-Daten angenommen und dann wie
>du vorschlägst für das Hauptprogramm ein Flag gesetzt, das die
>empfangenen Daten auswertet.

Schon mal gut.

>Bei SPI Kommunikation ist es nun so, dass ich den uC für den Motor als
>SPI Slave betreibe. Dann kann er selber die Daten nicht aktiv
>verschicken sondern muß sehr schnell die Daten bereitstellen,

Dass der AVR als SPI-Slave nicht so toll ist, ist bekannt.

>"Motor-Slave-uC" gibt es nicht, daher wartet der Master einige uSec bis
>er die Daten vom Slave heraustaktet.

OK.

> Wenn der Slave die Daten nicht
>rechtzeitig bereitstellt merkt der Master gar nicht, dass er nur Müll
>empfangen hat. Um das zu verhindern will ich sofort im Interrupt
>antworten.

Dein 1. Interrupt bekommt ja auch ein paar µS vom Master, warum nicht 
bei den nachfolgenden Bytes? Ausserdem scheint mir in deinem geposteten 
Coebesipiel dennoch deutlich mehr las nur die reine Datenübertragung 
drin zu sein. Funktionsaufrufe in ISRs sind beim AVR auch nicht so toll, 
wegen der Performance (der GCC sichert sehr viele Register).

>Einzige Alternative die ich sehe wäre noch den Slave auf Master
>umzuschalten und die Daten aktiv zu senden.

Das ist Murks. Bei SPI gibt es nur einen Master, und der ist fest 
vorgegeben.

von Falk B. (falk)


Lesenswert?

@  Peter II (Gast)

>wie soll ich das nun wieder verstehen? Dir ist doch bestimmt klar das
>sie auch nur im Ram liegen.

Praktisch schon, zwingend aber nicht. Ein Compiler kann die auch in 
Registern halten, auch wenn das real fast nie passiert. Es ist auch 
selten sinnvoll, als C-Programmierer derartig spezifische Annahmen über 
die Umsetzung des Compilers zu machen. Die Regeln und der Sinn von 
volatile sind klar definiert, die diversen Vorschläge sind nur 
Hackertricks mit vielen Nachteilen und wenigen Vorteilen.

von Peter II (Gast)


Lesenswert?

Falk Brunner schrieb:
> Praktisch schon, zwingend aber nicht.

was aber auch egal ist, dann man kann eh nicht von außen auf sie 
zugreifen.

> Die Regeln und der Sinn von
> volatile sind klar definiert, die diversen Vorschläge sind nur
> Hackertricks mit vielen Nachteilen und wenigen Vorteilen.

nachteil das ich ein Makro verwenden muss? sonst sehen ich keinen 
nachteil.

Oder meinst du als nachteil das es ziemlich GCC und Atmega spezifisch 
ist, wenn ja kann ich gut damit leben.

Ich sehe die Hauptverwendung von volatile bei den IO-Register dort muss 
jeder zugriff auf die register sofort gemacht werden, bei variablen 
entscheide ich im einzelfall wie ich es mache.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter II schrieb:
> Johann L. schrieb:
>> Wozu das ganze Leerzeichen-Geraffel???
>> Kost nur Zeit beim Tippen!
>
> Sache die nur einmal gemacht werden (tippen) müssen nicht schnell gehen,
> bei dingen die sicher oft wiederholen (ausführung) sollte man schon
> darauf achten.

Genau wie bei volatile-Hack auch. Der Spart Tipparbeit, denn:

Johann L. schrieb:

> Für jede Formulierung mit diesem Hack gibt es auch eine saubere
> Formulierung ohne.

Und noch präziser:

Für jede Formulierung mit diesem Hack gibt es auch eine saubere
Formulierung ohne, die zudem mindestens genauso effizient ist.

Es geht nur darum ein paar Zeilen Tipparbeit zu sparen.

von Coder (Gast)


Lesenswert?

Peter II schrieb:
> Warum alle zugriffe auf eine Variabel volatile machen und damit
> wesentlich schlechteren code erzeugen, wenn du eine davon stelle davon
> ausreichen würde. Das Kopieren in Temp variabel ist doch auch nur eine
> krücke.

Mit einer Kopie zu Arbeiten ist sprachlich sauberer. Ich persönlich 
überlasse es dem Compiler optimalen Code zu erzeugen, denn der Compiler 
ist meist besser als ich.

Zum Anderen finde ich aus konzeptioneller unlogisch eine normale 
Variable zu einem volatile Typ zu casten.

Tipparbeit sollte man sich nicht ersparen, denn solche Kniffe holen 
irgendwann mal einen ein.

von Stephan R. (stero)


Lesenswert?

Falk Brunner schrieb:
> Dein 1. Interrupt bekommt ja auch ein paar µS vom Master, warum nicht
> bei den nachfolgenden Bytes?

Ich bin mir nicht ganz sicher ob ich dich richtig verstehe.

Wenn ich die Antworten an den Master erst aus dem Hauptprogramm 
verschicken würde, nachdem dort Flag-gesteuert der Kommandointerpreter 
ausgeführt wird, dann vergeht evtl. ziemlich viel Zeit. Mehr als ein 
paar uSec. Der Master müßte profilaktisch solange warten, wie maximal 
ein Hauptprogramm Schleifendurchlauf dauert. Gut jetzt könnte man auf 
dem Master per Timer warten und pauschal z.B. 20mSec verstreichen 
lassen, bevor der Master das Byte abholt...

Im Moment sehe ich vor, vom Master ein Kommando an den Motor-Slave zu 
senden, der dann ein Byte innerhalb weniger uSec zurückgibt. Wenn die 
Daten sofort im Interrupt über z.B. get_motor_direction() beschafft 
werden können, dann kann ich sie auch sofort noch im Interrupt 
wegschicken und bin mir sicher, dass nicht mehr als ein paar uSec 
verstrichen sind. Nachteilig ist dabei, das eben viele Variablen als 
Volatile gekennzeichnet werden müssen. Wie ich oben gelernt habe müssen 
aber wenigstens nicht die Funktionen auch noch mit volatile 
gekennzeichnet werden, das erleichtert das Ändern der Motor-Bibliothek.


> Ausserdem scheint mir in deinem geposteten
> Codebeispiel dennoch deutlich mehr als nur die reine Datenübertragung
> drin zu sein. Funktionsaufrufe in ISRs sind beim AVR auch nicht so toll,
> wegen der Performance (der GCC sichert sehr viele Register).

Ja wahrscheinlich ist es besser auf die getter und setter Funktionen der 
Motor-Bibliothek zu verzichten und direkt z.B. die Variable für die 
Motordrehrichtung zu schreiben. Die muß dann natürlich auch in Volatile 
geändert werden und mittels extern noch veröffentlich werden.

Ich könnte auch einen Hybrid machen, dass ich in der Interruptfunktion 
nur Rückgabewerte an den Master sofort bearbeite und alle anderen 
Befehle per Flag im Hauptprogramm. Da ich für das Senden der Infos zum 
Master sowieso fast alle Variablen als Volatile deklarieren muß, kann 
ich aber auch gleich die Befehle ohne Rückangwort an den Master im 
Interrupt ausführen.

>>Einzige Alternative die ich sehe wäre noch den Slave auf Master
>>umzuschalten und die Daten aktiv zu senden.
> Das ist Murks. Bei SPI gibt es nur einen Master, und der ist fest
> vorgegeben.
OK, dann werde ich das auch wohl sein lassen :)

Wäre das so eine ordentliche Lösung?

von Peter II (Gast)


Lesenswert?

Coder schrieb:
> Mit einer Kopie zu Arbeiten ist sprachlich sauberer. Ich persönlich
> überlasse es dem Compiler optimalen Code zu erzeugen, denn der Compiler
> ist meist besser als ich.

das ist doch ein wiederspruch in sich. Wenn der compiler optimalen code 
erzeugen würden, dann bräuchte man keine hilfsvariable, sonder könnte es 
schreiben wie ich es will.

> Tipparbeit sollte man sich nicht ersparen, denn solche Kniffe holen
> irgendwann mal einen ein.
bis jetzt hat noch niemand einen wirklichen nachteil dieser Lösung 
genannt.

von Coder (Gast)


Lesenswert?

Peter II schrieb:
> das ist doch ein wiederspruch in sich. Wenn der compiler optimalen code
> erzeugen würden, dann bräuchte man keine hilfsvariable, sonder könnte es
> schreiben wie ich es will.

Ich möchte gar nicht abstreiten, dass die oben genannte Lösung in deiner 
Konstellation schnelleren Code liefert. Und ich habe auch kein Problem 
damit, den Inhalt einer volatile-Variable in einer Hilfvariable zu 
kopieren. Das ist Formal sauber.

Aber ich denke, dass meine Aussage ist kein Widerspruch ist. Es eine 
Frage wie man die Sprache einsetzt und seine Funktionen programmiert. 
Denn die Leute, die den Compiler programmiert haben, sind ganz bestimmt 
besser als Ich (man muss die Optimierungen natürlich einschalten).

IMHO deklariert man eine Variable so, wie man sie verwenden möchte; Also 
sie entweder volatile oder nicht.

von Peter II (Gast)


Lesenswert?

Coder schrieb:
> Aber ich denke, dass meine Aussage ist kein Widerspruch ist. Es eine
> Frage wie man die Sprache einsetzt und seine Funktionen programmiert.
> Denn die Leute, die den Compiler programmiert haben, sind ganz bestimmt
> besser als Ich (man muss die Optimierungen natürlich einschalten).

leider stimmt das so nicht immer.

schönes Beispiel:
1
int x;
2
if ( x > 0.1 ) {
3
}

hier verwendet der compiler einen float vergleich - schön langsam auf 
einem AVR.

> IMHO deklariert man eine Variable so, wie man sie verwenden möchte; Also
> sie entweder volatile oder nicht.
ich will ja nicht das er in der ISR die variabel als volatile ansieht, 
das ist ja das Problem. Eventuell könnte man ja die ISR in eine extra C 
datei auslagern und die variabel in der main als volatile deklarieren. 
Also 2 verschiende deklarationen für die gleiche Variable.

von Coder (Gast)


Lesenswert?

Also floats sind auf jedem uC immer langsam, die nativ keine 
Fließkommazahlen können!

(1) Also Variablen, die Du in deiner ISR verwendest UND "parallel" zur 
ISR-Context von deiner main verwendet werden, müssen als volatile 
deklariert werden.

(2) Wenn Du in deiner main() auf Variablen zugreifst die auch die ISR 
verwendet, solltest Du indirekt darauf zugreifen, z.B. über die Get- und 
Set-Routinen. Weil in den Get- und Set-Routinen muss sichergestellt 
werden, dass während des Zugriff in der main die ISR zuschlägt und 
ausgerechnet die Variable ändert, die Du  gerade bearbeitest.

(3) Wenn Du natürlich die gesamte Ansteuerung des Motor über die ISR 
machst, benötigst Du kein volatile. Dann sollte aber alles in einem 
modul sein.

von Stephan R. (stero)


Lesenswert?

Coder schrieb:

> (2) Wenn Du in deiner main() auf Variablen zugreifst die auch die ISR
> verwendet, solltest Du indirekt darauf zugreifen, z.B. über die Get- und
> Set-Routinen. Weil in den Get- und Set-Routinen muss sichergestellt
> werden, dass während des Zugriff in der main die ISR zuschlägt und
> ausgerechnet die Variable ändert, die Du  gerade bearbeitest.
16 Bit Variablen werde ich dann mit ATOMIC_BLOCK in der Bibliothek und 
im Hauptprogramm schützen. Bei den 8-Bit Werten kann ich 
vorraussichtlich darauf verzichten. Ich weiß, dass man auch bei 8-Bit 
aufpassen muß z.B. bei &= und |= Operationen.

> (3) Wenn Du natürlich die gesamte Ansteuerung des Motor über die ISR
> machst, benötigst Du kein volatile. Dann sollte aber alles in einem
> modul sein.
Der Motor ist ein Brushless-Typ. Die Treibersoftware erstreckt sich über 
viele verschiedene Files. Also leider nichts, was so in die ISR passen 
würde.

von Coder (Gast)


Lesenswert?

Abschließend mal ganz was anderes.
Wie wäre es alternativ mit einer Commando Queue, also einer FIFO über 
die dein Program mit deinem Treiber kommuniziert? Könnte der "Rest" 
deiner Motor-Treiber-Firmware dann so funktionieren, dass das Ergebnis 
über die "Commando-Queue" weitergibt, so dass die Steueralgorhitmen 
nicht auf den Motor-Hardware direkt zugreift?

Ansonsten habe ich auch keine Idee mehr.

von Stephan R. (stero)


Lesenswert?

Coder schrieb:
> Wie wäre es alternativ mit einer Commando Queue, also einer FIFO über
> die dein Program mit deinem Treiber kommuniziert? Könnte der "Rest"
> deiner Motor-Treiber-Firmware dann so funktionieren, dass das Ergebnis
> über die "Commando-Queue" weitergibt, so dass die Steueralgorhitmen
> nicht auf den Motor-Hardware direkt zugreift?
Wenn die schnelle Variante im Interrupt nicht sauber funktioniert, wäre 
das noch eine Alternative.

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Falk Brunner schrieb:
>> Praktisch schon, zwingend aber nicht.
>
> was aber auch egal ist, dann man kann eh nicht von außen auf sie
> zugreifen.
>
>> Die Regeln und der Sinn von
>> volatile sind klar definiert, die diversen Vorschläge sind nur
>> Hackertricks mit vielen Nachteilen und wenigen Vorteilen.
>
> nachteil das ich ein Makro verwenden muss? sonst sehen ich keinen
> nachteil.

Der Nachteil ist, dass du den Einsatz des Makros vergessen kannst.
Mit entsprechenden Auswirkungen auf das Programm.

Vergisst du in der Umkehrung das Umkopieren in eine temporäre Variable, 
dann ist das Programm immer noch korrekt, wenn auch ein wenig langsamer.


Im Sinne der defensiven Programmierung nehme ich lieber die Variante, 
die mir einen Fehler verzeiht bzw. die Variante, bei der ich weniger 
schwerwiegende Fehler machen kann.

von Peter II (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Der Nachteil ist, dass du den Einsatz des Makros vergessen kannst.
> Mit entsprechenden Auswirkungen auf das Programm

man kann auch das volatile vergessen.

Davor warnt einem auch niemand, als Programmieren sollte man halt schon 
ein wenig wissen was man macht.

von Coder (Gast)


Lesenswert?

Peter II schrieb:
> man kann auch das volatile vergessen.
>
> Davor warnt einem auch niemand, als Programmieren sollte man halt schon
> ein wenig wissen was man macht.

Man kann sich auch vorher Gedanken, von welchen Typ die Variable sein 
sollte. Je weniger typecasts man machen muss, desto besser.

Und defensives Programmieren ist nicht immer langsamer. Ich kann nur 
nochmal betonen: die Optimierer der Compiler i.d.R. besser sind , als 
man selbst. Man muss seinen Code so schreiben, dass der Compiler 
Optimierungsstrategien anwenden kann. Und bevor man anfängt wild zu 
optimieren, sollte das Programm erstmal funktionieren.

von Peter II (Gast)


Lesenswert?

Coder schrieb:
> Und bevor man anfängt wild zu
> optimieren, sollte das Programm erstmal funktionieren.

ob ich nun schreibe
1
char* s
2
for( int x = 0; x < strlen(s); x++ ) {
3
   s[x] = uppper(s[x]);
4
}

oder gleich schreibe
1
char* s
2
char* c = s;
3
while (*c) {
4
   *c = uppper(*c);
5
   ++c;

ist der gleiche aufwand und gleich stark optimiert. Beides läuft 
(hoffentlich) fehlfrei. Nur weil ich ein I7 habe mache ich immer noch 
gedanken über die Programmlaufzeit.

Jeder Optimiert bei der Programmierung, die frage ist nur auf welchen 
Level.

von Coder (Gast)


Lesenswert?

Peter II schrieb:
> Jeder Optimiert bei der Programmierung, die frage ist nur auf welchen
> Level.

Ja natürlich.

Und abschließend
Wenn der Optimierer aktiv ist, liefern folgende Beispiele
1
#include <stdint.h>
2
3
volatile uint8_t VolatileVar;
4
5
void main(void)
6
{
7
   uint8_t Temp;
8
   while(1)
9
   {
10
       Temp=VolatileVar;
11
  if (Temp==1U)
12
  {
13
      ++VolatileVar;
14
  }
15
   }
16
}

sowie
1
#include <stdint.h>
2
3
volatile uint8_t VolatileVar;
4
5
void main(void)
6
{
7
    while(1)
8
    {
9
       if (VolatileVar==1U)
10
       {
11
     ++VolatileVar;
12
       }
13
    }
14
}

denselben Asssembler Code. Für den übersetzten Code macht es nichts, ob 
man eine Temp Variable verwendet. Es ist aber sprachlich sauber und 
vorzuziehen. Der volatile-cast-hack ist absolut unnötigt und ist 
fehlerträchtig.

Aber das muss du für Dich entscheiden.
Einen schönen Tag noch.

von Peter II (Gast)


Lesenswert?

Coder schrieb:
> denselben Asssembler Code. Für den übersetzten Code macht es nichts, ob
> man eine Temp Variable verwendet. Es ist aber sprachlich sauber und
> vorzuziehen. Der volatile-cast-hack ist absolut unnötigt und ist
> fehlerträchtig.

noch einmal, es geht mir nicht um die main! Mich stört die volatile 
zugriff in der ISR, wenn ich die Variabel als voltile kennzeichne. Um 
das zu umgehen muss ich dort mit einer Tmp variable arbeiten.

Damit hat das beispiel leider das thema verfehlt.

Ich möchte die globale variable in der ISR normal haben und in allen 
andere funktionen volatile.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

@Coder: Gib's einfach auf. Wer nix dazulernen will, der will eben nix 
dazulernen...

von Coder (Gast)


Lesenswert?

Hm. Habe ich mich wirklich so schlecht ausgedrückt? Habe ich das 
wirklich falsch verstanden?

1) Dem Threadersteller hatte ich kurz und knapp geschrieben, wie man 
meines Erachtens mit volatile deklarierten Variablen umgeht. Also wie 
man Variablen verfahren sollte, die sich eine ISR-Context und 
Main-Context bzw. mehrere Threads teilen. Wenn jemand eine andere 
bessere Lösung hat, darf er diese gerne mitteilen.

2) Peter II sagt in seinen vorhergehenden Postings

Peter II schrieb:
> Warum alle zugriffe auf eine Variabel volatile machen und damit
> wesentlich schlechteren code erzeugen, wenn du eine davon stelle davon
> ausreichen würde. Das Kopieren in Temp variabel ist doch auch nur eine
> krücke.

a)Also vermute ich, er möchte deswegen wohl in seiner ISR seine 
Variablen per default nicht als volatile deklarieren , weil er 
befürchtet es sei zu langsam, zu schlechter? Diese Variablen braucht er 
aber in anderen Funktionen (oder Module?) als volatile?

b)Hatte ich ich nicht geschrieben, dass meines Erachtens eine Variable 
entweder immer volatile ist oder nicht volatile ist, und dass das ein 
ganz schlechtes Konzept ist? Und ich stattdessen zu einer Lösung wie 1) 
tendiere.

c)Hatte ich Peter II mit meinem Beispiel nicht versucht zu überzeugen, 
dass im Zweifel eine punktuelle Optimierung der Compiler durchaus selber 
hinkriegt, wenn die Optimierungen eingeschaltet sind?

von Peter II (Gast)


Lesenswert?

Coder schrieb:
> Hatte ich Peter II mit meinem Beispiel nicht versucht zu überzeugen,
> dass im Zweifel eine punktuelle Optimierung der Compiler durchaus selber
> hinkriegt, wenn die Optimierungen eingeschaltet sind?

das Beispiel war unsinn, das hier das gleich rauskommt ist absolut klar.

> Hatte ich ich nicht geschrieben, dass meines Erachtens eine Variable
> entweder immer volatile ist oder nicht volatile ist, und dass das ein
> ganz schlechtes Konzept ist? Und ich stattdessen zu einer Lösung wie 1)
> tendiere.
ja geschrieben haben wir alles viel, aber das sagt nicht das es immer 
das richtige ist.

Fakt ist das man das volatile nicht in der ISR braucht und es dort (ohne 
die zustätzelichen Temp Variablen ) zu schlechter optimierten code 
führt.

Fakt ist auch das man ein volatile zugriff in alles anderen funktionen 
braucht.

Damit hat man die Möglichkeiten:

- die variable als volatile kennzeichen und Perfomance verlust in kauf 
nehmen.

- die variabel als voaltile kennzeichen und Temp variabel einführen und 
damit eine doppelete Datenhaltung haben - was auch zu fehler führen 
kann.

- variable nicht volatile machen und einen cast in den NICHT-isr 
funktionen machen. (darf man nur nicht vergessen)

Ich habe alles schon verwendet, weil es verschiedene Anforderungen gibt. 
Die erste lösung ist die "schönste" aber halt nicht die schnellste, und 
dafür gibt es ebend 2 alternativen.

von Coder (Gast)


Lesenswert?

Belassen wir es einfach.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Peter II schrieb:
> - die variable als volatile kennzeichen und Perfomance verlust in kauf
> nehmen.

Bleibt die Frage bestehen, ob diese Performanceverluste auch nur in 
irgendeiner Weise relevant sind - was natürlich davon abhängt, wie oft 
die ISR so typischerweise aufgerufen wird und wie schnell in der ISR auf 
irgendwas reagiert werden soll. Um mehr als eine Handvoll Takte wird es 
jedenfalls nicht gehen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Coder schrieb:
> Hm. Habe ich mich wirklich so schlecht ausgedrückt?

Nö.

> Habe ich das wirklich falsch verstanden?

Ja. Ich meinte nicht dich, sondern deinen Kommunikationspartner. Und das 
es offenbar nicht lohnt, sich die Finger fusselich zu tippen, wenn eh 
alles abperlt.

> 1) Dem Threadersteller hatte ich kurz und knapp geschrieben, wie man
> meines Erachtens mit volatile deklarierten Variablen umgeht. Also wie
> man Variablen verfahren sollte, die sich eine ISR-Context und
> Main-Context bzw. mehrere Threads teilen. Wenn jemand eine andere
> bessere Lösung hat, darf er diese gerne mitteilen.
>
> 2) Peter II sagt in seinen vorhergehenden Postings
>
> Peter II schrieb:
>> Warum alle zugriffe auf eine Variabel volatile machen und damit
>> wesentlich schlechteren code erzeugen, wenn du eine davon stelle davon
>> ausreichen würde. Das Kopieren in Temp variabel ist doch auch nur eine
>> krücke.
>
> a)Also vermute ich, er möchte deswegen wohl in seiner ISR seine
> Variablen per default nicht als volatile deklarieren, weil er
> befürchtet es sei zu langsam, zu schlechter? Diese Variablen braucht er
> aber in anderen Funktionen (oder Module?) als volatile?

Ja. Eine Variable ist entweder volatile oder nicht volatile. Wenn einem 
die 1 Zeile zum Anlegen einer lokalen Variable zu viel ist, dann machen 
manche eben lieber einen Hack[tm] mit dem Pointer-Cast, der

• Schlechter Stil ist, z.B. im Hinblick auf Wartbarkeit und
  passive Programmierung

• Keine bessere Performance hat als die saubere Lösung

• U.u. sogar schlechtere Performance hat, siehe die Anmerkung zu
  Aliasing

• Noch wüstere Makros erfordert wenn man mit Zeigern hantiert
  – und mit dem Cast dann mit Zeigern auf Zeigern und irgendwo das
  volatile reinfutscheln muss

• Kein Standard-C ist sondern eine GNU-Erweiterung (typeof)

• Ohne typeof sieht der Code noch "expertiger" aus

• Der Performance-Verlust wahrscheinlich eh schnuppe ist, nach dem
  Motto "Herr Compiler, ich weiß da was besser und machn Experten-Hack"
  d.h. die Optimierung fällt in die Kategorie "Pyschologische
  Optimierung" bzw. "Angstoptimierung".

> b)Hatte ich ich nicht geschrieben, dass meines Erachtens eine Variable
> entweder immer volatile ist oder nicht volatile ist, und dass das ein
> ganz schlechtes Konzept ist?
> Und ich stattdessen zu einer Lösung wie 1) tendiere.

Seh ich auch so.

> c)Hatte ich Peter II mit meinem Beispiel nicht versucht zu überzeugen,
> dass im Zweifel eine punktuelle Optimierung der Compiler durchaus selber
> hinkriegt, wenn die Optimierungen eingeschaltet sind?

Versucht schon...

von Peter II (Gast)


Lesenswert?

Johann L. schrieb:

> Wenn einem die 1 Zeile zum Anlegen einer lokalen Variable zu viel ist
dann habe ich 2 Variabelen dir irgendwie gleich sind aber dann doch 
nicht.

> Der Performance-Verlust wahrscheinlich eh schnuppe ist, nach dem
>   Motto "Herr Compiler, ich weiß da was besser und machn Experten-Hack"
>   d.h. die Optimierung fällt in die Kategorie "Pyschologische
>   Optimierung" bzw. "Angstoptimierung".

es zwingt euch niemand es so zu machen.

Und ich bin wirklich nicht überzeugt von der Qualtität der optimierung 
des compilers (ich könnte aber auch keinen besseren schreiben!) und 
schaue mit kritische codesequenzen gerne im ASM code an und versuche 
dann die code so zu umzuschreiben das es der compiler es begreift.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Ja. Ich meinte nicht dich, sondern deinen Kommunikationspartner. Und das
> es offenbar nicht lohnt, sich die Finger fusselich zu tippen, wenn eh
> alles abperlt.

Dann hör lieber auch auf damit. Ich habs schon gestern aufgegeben. Peter 
weiß es immer besser und schreibt auch jedesmal eine neue Antwort 
darauf, wo immer dasselbe drin steht.

Beton bleibt Beton.

von Peter II (Gast)


Lesenswert?

Frank M. schrieb:
> Ich habs schon gestern aufgegeben. Peter
> weiß es immer besser und schreibt auch jedesmal eine neue Antwort
> darauf, wo immer dasselbe drin steht.

als ob eure Argumente sich ändern würden.

Ich sehen wenigsten ein das es mehre wege zum Ziel gibt.

von Stephan R. (stero)


Lesenswert?

So, die Motorsteuerung läuft jetzt einwandfrei gesteuert aus dem 
SPI-Interrupt heraus. Im Interrupt rufe ich nun die Setter und Getter 
des Motortreibers auf. Die Variablen, auf die die Setter und Getter 
zugreifen sind jetzt alle als Volatile deklariert. Die Antworten an den 
SPI-Master gehen auch sauber raus. Ich habe im Master erstmal eine 
Wartezeit von 10uSec auf den Slave eingestellt, sicher geht auch noch 
weniger.

Das Makro hätte mir auch keine Änderung am Motortreiber erspart, 
deswegen nehme ich solange es die Performance zuläßt die althergebrachte 
Lösung. Wenn es  performancekritisch wird, werde ich mich sicher an das 
Cast-Macro erinnern.

Umkopieren der Volatile Variablen mit mehreren Zugriffen im Interrupt 
mit dem Ziel,  das der Compiler schnell darauf zugreifen kann, ist wohl 
immer eine gute Idee, wenn Performance nicht völlig unwichtig ist.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter II schrieb:

> Und ich bin wirklich nicht überzeugt von der Qualtität der optimierung
> des compilers

Weder bei der Cast-Variante noch bei der Variante mit der 
temporär-Variable handelt es sich um eine Optimierung, die ein Compiler 
ausführt, denn beide ändern die Semantik des Programms.

Der Compiler ist natärlich and die Semantik der Sprachspezifikation 
gebunden — ansonsten wäre er ziemlich sinnfrei.

Für Optimierungen, die die Semantik des Programmes ändern, ist also der 
Programmierer verantwortlich.

Anderes Beispiel wäre die Auswahl eines Sortieralgorithmus': Verlangt 
man vom Compiler ein qsort, wird er ein qsort einbauen. Wenn man einen 
anderen Algorithmus möchte, muss man selbst Hand anlegen an den Code. 
Und zwar an den Code der Anwendung, nicht an den des Compilers.

Und beim Handanlegen hat eben jeder unterschiedliche Qualitätsmaßstäbe 
und daran wie der resultierende Code formal aussehen sollte — auch wenn 
er wie beim obigen Beispiel zum gleichen Binärcode führt (modulo 
Aliasing).

Falls du dich auf Optimerungen in Reichweite des Compilers beziehst:
GCC is Free Software. Anybody can contribute. Patches welcome.

von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:
> Für Optimierungen, die die Semantik des Programmes ändern, ist also der
> Programmierer verantwortlich.

Manchmal aber dann doch auch der des Compiler. Immerhin ist schon 
Benchmark-Beschiss aufgeflogen, bei denen der Compiler klammheimlich den 
Algorithmus "modifiziert" hat, weil er das Pattern des Benchmarks 
erkannte und den Code passend durch eine schnellere Variante ersetzte.

von Peter II (Gast)


Lesenswert?

Johann L. schrieb:
> Für Optimierungen, die die Semantik des Programmes ändern, ist also der
> Programmierer verantwortlich.

warum optimiert er dann nicht

[c]
int a;
if ( a > 0.1 ) { };
[\c]

laut C muss er den vergleich mit float machen. Aber wenn der 
sicherstellen kann das das ergebniss gleich ist darf er optimieren.

Damit könnte er hier ein int vergleich machen - tut er aber nicht weil 
es ein dummer compiler ist.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. schrieb:
> Johann L. schrieb:
>> Für Optimierungen, die die Semantik des Programmes ändern, ist also der
>> Programmierer verantwortlich.
>
> Manchmal aber dann doch auch der des Compiler. Immerhin ist schon
> Benchmark-Beschiss aufgeflogen, bei denen der Compiler klammheimlich den
> Algorithmus "modifiziert" hat, weil er das Pattern des Benchmarks
> erkannte und den Code passend durch eine schnellere Variante ersetzte.

GCC?

von Coder (Gast)


Lesenswert?

@Peter II
Na weil a sich zur Laufzeit ändert. Und das kann kein Compiler.

@Stephan R.
Schön zu hören dass es funktioniert.

@Johann
Ich habs' nicht auf mich bezogen. Die Fragen waren eher rhetorisch, weil 
Peter II mich mit seinen "Optimierungen" zum verzweifeln bringt (ich bin 
bestimmt kein C-Guru und verzapfe auch viel Mist)

von Peter II (Gast)


Lesenswert?

Coder schrieb:
> @Peter II
> Na weil a sich zur Laufzeit ändert. Und das kann kein Compiler.

nein der code ändert sich nicht zu laufzeit!
1
int a;
2
if ( a > 0.1 ) { };

er sollte selber auf die idee kommen:
1
int a;
2
if ( a > (int)0.1 ) { };

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter II schrieb:
> Johann L. schrieb:
>> Für Optimierungen, die die Semantik des Programmes ändern, ist also der
>> Programmierer verantwortlich.
>
> warum optimiert er dann nicht
>
1
int a;
2
if ( a > 0.1 ) { };
> laut C muss er den vergleich mit float machen. Aber wenn der
> sicherstellen kann das das ergebniss gleich ist darf er optimieren.
>
> Damit könnte er hier ein int vergleich machen - tut er aber nicht weil
> es ein dummer compiler ist.

Dann nimm einen anderen Compiler.

Oder verbessere den vorliegenden Compiler.

GCC ist wie gesagt Freie Software, zu der jeder beitragen kann. Und 
Beträge kommen von demjenigen, der sich darum kümmert.

Wie ist übrigens die Bug-Nummer zum obigen Code?

Die Grundvoraussetzung für das Beheben eines Problems ist, daß das 
Problem mitgeteilt wird.

Und möglicherweise hat sich auch noch keiner drum gekümmert, weil jeder, 
den die fehlende Optimierung an dieser Stelle stört, die triviale, 
naheliegende Änderung an seinem Code macht, die den Vergleich auf 
int-Ebene ausführt.

Wenn du wiklich wissen willst, warum die Optimierung nicht in GCC 
drinne ist, dann frag die GCC-Entwicker in der dafür vorgesehenen 
Mailing-Liste gcc-help@gcc.gnu.org

von Coder (Gast)


Lesenswert?

@Peter II

Nicht der Code der Inhalt!
Woher weiss der Compiler was in der Variable a ist? Und nein er 
initalisiert das nicht und eigentlich sollte dein Compiler eine Warnung 
erzeugen, dass a nicht initialisiert ist.

was wird wohl aus einem (int)0.1? Ganz blödes beispiel.

Feierabend.

von Peter II (Gast)


Lesenswert?

Johann L. schrieb:
> die triviale,
> naheliegende Änderung an seinem Code macht, die den Vergleich auf
> int-Ebene ausführt.

erstaunlich was alles naheliegend ist - hättest du es denn gewussst?

Und ein harter cast ist ja wohl keine lösung, du du uns oben bei dem 
volatile schon erklärt hast.

von Peter II (Gast)


Lesenswert?

Coder schrieb:
> Woher weiss der Compiler was in der Variable a ist?
aus der Deklaration? Wie auch bei jeder anderen Variable.

> Und nein er
> initalisiert das nicht und eigentlich sollte dein Compiler eine Warnung
> erzeugen, dass a nicht initialisiert ist.

es spielt keine rolle was in a drin steht, irgendein wert zwischen 
INT_MIN und INT_MAX

> was wird wohl aus einem (int)0.1? Ganz blödes beispiel.
wo ist das Problem mit dem Beispiel? Es geht ja darum das in a keine 
konstante ist, sonst hätte ich sie ja hingeschrieben. Es soll eine ganz 
normale variabel sein die jeden möglichen inhalt aus ihren wertebereich 
annehmen kann.

Aber für dich noch mal ohne warnung:
1
int a = rand();
2
if ( a > 0.1 ) {
3
};

von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:
> GCC?

Nein.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Peter II schrieb:
> warum optimiert er dann nicht
>
> int a;
> if ( a > 0.1 ) { };
>
> laut C muss er den vergleich mit float machen. Aber wenn der
> sicherstellen kann das das ergebniss gleich ist darf er optimieren.

Wenn ich Code schreiben würde, in dem eine Integer-Variable mit einer
nichtganzzahligen Konstante verglichen wird, wäre das 150%ig garantiert
keine Absicht, sondern ein Fehler. Dieser Fehler muss vom Compiler nicht
auch noch optimiert werden. Wenn ich überhaupt eine spezielle Behandlung
dieses Falls erwarten würde, dann allenfalls eine 3 Meter hohe Warnmel-
dung in knalligstem Rot :)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter II schrieb:
> Johann L. schrieb:
>> die triviale, naheliegende Änderung an seinem Code macht,
>> die den Vergleich auf int-Ebene ausführt.
>
> erstaunlich was alles naheliegend ist - hättest du es denn gewussst?

Ja.

> Und ein harter cast ist ja wohl keine lösung, du du uns oben bei dem
> volatile schon erklärt hast.

Der volatile-Cast ist nochmal eine ganz andere Liga, denn er ist zum 
einen ein Pointer-Case und zum anderen fuhrwerkt er mit Qualifiern rum.

Nochmal zu dem float-Beispiel:

Welche Bugnummer hat das im GCC-Bugzilla?

Dein Beispielcode ist übrigens weder gültiges C, noch zeigt er den von 
dir beschriebenen Effekt — zumindest wenn man deinen hingeschlunzten 
Zeilen zu einen gültigen Testfall ergänzt, der einen Compile-Lauf 
übersteht ohne zig Syntax-Fehlern zu produzieren.

von Peter II (Gast)


Lesenswert?

Johann L. schrieb:
> Nochmal zu dem float-Beispiel:
>
> Welche Bugnummer hat das im GCC-Bugzilla?
keine Ahnung ich habe keinen angelegt. (ich habe es einmal bei PHP 
versucht und dann aufgegen)

> Dein Beispielcode ist übrigens weder gültiges C, noch zeigt er den von
> dir beschriebenen Effekt — zumindest wenn man deinen hingeschlunzten
> Zeilen zu einen gültigen Testfall ergänzt, der einen Compile-Lauf
> übersteht ohne zig Syntax-Fehlern zu produzieren.

so hier ein beispiel, damit du es auch nachvollziehen kannst:
1
#include <stdio.h>
2
#include <stdlib.h>
3
4
int main() {
5
6
  int a = rand();
7
  if ( a > 0.1 ) {
8
     printf("test1\n");
9
  }
10
  return 0;
11
}

erzeugt folgenden code:

gcc -Wall -O2 -S test3.cpp

main:
.LFB19:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        andl    $-16, %esp
        subl    $32, %esp
        call    rand
        movl    %eax, 28(%esp)
        fildl   28(%esp)
        fldl    .LC0
        fxch    %st(1)
        fucompp
        fnstsw  %ax
        sahf
        jbe     .L2
        movl    $.LC1, (%esp)
        call    puts
.L2:
        xorl    %eax, %eax
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
.LFE19:
        .size   main, .-main
        .section        .rodata.cst8,"aM",@progbits,8
        .align 8
.LC0:
        .long   -1717986918
        .long   1069128089
        .ident  "GCC: (Debian 4.7.1-2) 4.7.1"
        .section        .note.GNU-stack,"",@progbits

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter II schrieb:
> Johann L. schrieb:
>> Nochmal zu dem float-Beispiel:
>>
>> Welche Bugnummer hat das im GCC-Bugzilla?
> keine Ahnung ich habe keinen angelegt.

Na dann leg ein Bugreport an!

Anstatt GCC-Entwickler als dumm zu bezeichnen und hellseherische 
Fähigkeiten zu erwarten.

Dich hier darüber aufzuregen bringt rein garnix.

Eine erwachsener Umgang damit ist, bei GCC-Entwicklern nachzufragen, 
warum das so ist, selber das Problem zu beheben — immerhin bist du ja 
nicht dumm — oder eben zumindest einen aussagekräftigen Bugreport zu 
schreiben.

Und überleg dir, ob die Optimierung wirklich zulässig ist, etwa wenn int 
nicht exakt durch double darstellbar ist, bevor es peinlich wird. Und 
daß die ganzen Typumwandlungen dabei unabhängig vom eingestellten 
Rounding-Mode sind.

von Peter II (Gast)


Lesenswert?

Johann L. schrieb:
> Anstatt GCC-Entwickler als dumm zu bezeichnen und hellseherische
> Fähigkeiten zu erwarten.
was soll das jetzt? Ich habe keinmal schlecht über die entwickler 
gesprochen. Habe überhaupt keine Grund dazu. Ich wollte nur zeigen das 
man nicht jeden code dem compiler vorwerfen kann und hoffen das er schon 
optimiert.

du hast doch geschieben:

>  Der Performance-Verlust wahrscheinlich eh schnuppe ist, nach dem
>  Motto "Herr Compiler, ich weiß da was besser und machn Experten-Hack"
>  d.h. die Optimierung fällt in die Kategorie "Pyschologische
>  Optimierung" bzw. "Angstoptimierung".

ich habe dir nur ein einfaches beispiel gezeigt wo das nicht stimmt.


> Dich hier darüber aufzuregen bringt rein garnix.
ich rege mich überhaupt nicht auf, es war nur als bespiel gedacht das 
man auch noch selber denken sollte.

> Und überleg dir, ob die Optimierung wirklich zulässig ist, etwa wenn int
> nicht exakt durch double darstellbar ist, bevor es peinlich wird.
jetzt hast du aber lange gesucht um noch etwas zu finden. Dann schreib 
doch gleich mal hin in welchen fall das nicht stimmt.

> Eine erwachsener Umgang damit ist, bei GCC-Entwicklern nachzufragen,
> warum das so ist, selber das Problem zu beheben — immerhin bist du ja
> nicht dumm — oder eben zumindest einen aussagekräftigen Bugreport zu
> schreiben.
ist denn eine nicht vorhanden optimierung ein Bug? Müsste man das nicht 
als Feature Request einreichen?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter II schrieb:
> Johann L. schrieb:
>> Und überleg dir, ob die Optimierung wirklich zulässig ist, etwa wenn int
>> nicht exakt durch double darstellbar ist, bevor es peinlich wird.
> jetzt hast du aber lange gesucht um noch etwas zu finden. Dann schreib
> doch gleich mal hin in welchen fall das nicht stimmt.

Ist n_f der float, der aus dem int n hervorgeht, dann ist
mit ε=0 falls n exakt darstellbar ist und ε≠0 sonst. Das hängt u.a. 
davon ab, wie die Implementierung den Integer repräsentiert, wie den 
Floating-Typ, und wie groß n ist. Weil die Optimierung die Semantik des 
Programms nicht verändern darf, muss sichergestellt sein, daß der 
Vergleich das gleiche Ergebnis liefert, wenn n durch n+ε erstetzt wird. 
Dies ist nicht für alle denkbaren Implementierungen und Vergleiche der 
Fall.

> ist denn eine nicht vorhanden optimierung ein Bug? Müsste man das nicht
> als Feature Request einreichen?

Die Bug-Nummern in GCC bzw. binutils bugzilla beginnen auf PR, kurz für 
"Problem Report". Dazu zählen auch die "missed-optimization" in Feld 
Keywords.

Und wähle eine populäres Target wie x86 anstatt avr. Den aktuellen 
Compiler hast du ja.

Ausserdem wird
   http://gcc.gnu.org/bugs/#need
gerne gelesen.

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.