www.mikrocontroller.net

Forum: Compiler & IDEs Verhindern der wegoptimierung von for(;;) beim GCC


Autor: Flo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute, köönt ihr mir eventuell sagen wie ich bei diesem Code:
#include <avr/io.h>
#include <stdio.h>
#include <inttypes.h>
#include <stdint.h>
#include <avr/eeprom.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/pgmspace.h>

void main(void) __attribute__((noreturn));

#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
#define BAUD 19200L

uint8_t i=0;
char c;
char s[10];
char input[10];
char gcc[] PROGMEM = "Boot up Ready, OS Compiliert am "__DATE__" um "__TIME__" mit GCC Version "__VERSION__"\r\n";


void uart_puts (char *s);
int uart_putc(unsigned char c);
uint8_t uart_getc(void);
void uart_puts_p(const char *text);
uint8_t uart_puffer_check(void);//Erkennung für neue Zeichen

#define max 20
volatile uint8_t puffer[max]; 
volatile uint8_t* lesezeiger; 
volatile uint8_t* schreibzeiger; 


void main(void)
{
  UCSRB = 1<<TXEN | 1<<RXEN;              // UART TX einschalten UART RX einschalten
  UCSRC = 1<<URSEL | 1<<UCSZ1 | 1<<UCSZ0;           // Asynchron 8N1
  UBRRH = UBRR_VAL >> 8;
  UBRRL = UBRR_VAL & 0xFF;
  UCSRB |= (1<<RXCIE);
  //uart_puts_p(gcc);

  lesezeiger=puffer; 
  schreibzeiger=puffer;

  sei();
  for(;;)
  {
    
    if(uart_puffer_check()==1)
    {
      
      input[i]=uart_getc();
      i++;
      if(input[i-1]==0x0d)
      {
        input[i-1]=0;
        i=0;
        //uart_puts(input);
      }
    }
    else
    {
      
    }
  }
}

uint8_t uart_getc(void)
{ 
  uint8_t datenbyte=0; 
 
  if(schreibzeiger!=lesezeiger)
  { 
      datenbyte=*lesezeiger;//Auslesen des Ringpuffers 
      lesezeiger++; 
     if(lesezeiger==puffer+max) lesezeiger=puffer; 
   } 
  return datenbyte; 
} 

int uart_putc(unsigned char c)
{
    while (!(UCSRA & (1<<UDRE)))
    {
    }

    UDR = c;
    return 0;
}

void uart_puts (char *s)
{
    while (*s)
    {   
        uart_putc(*s);
        s++;
    }
}

void uart_puts_p(const char *text)
{
    char Zeichen;
 
    while (Zeichen = pgm_read_byte(text))
    {   /* so lange, wie mittels pgm_read_byte ein Zeichen vom Flash gelesen
           werden konnte, welches nicht das "String-Endezeichen" darstellt */
 
        /* Das gelesene Zeichen über die normalen Kanäle verschicken */
        uart_putc(Zeichen);
        text++;
    }
}

uint8_t uart_puffer_check(void)
{ 
if(schreibzeiger!=lesezeiger) 
  return 1; 
else return 0; 
} 

ISR (USART_RXC_vect)
{ 
    *schreibzeiger=UDR; //empfangenes Datenbyte abspeichern 
  uart_putc(*schreibzeiger);
    schreibzeiger++; 
    if(schreibzeiger==puffer+max) 
    schreibzeiger=puffer; 
} 

verhindern kann das die For Schleife wegoptimiert wird, der code ist 
noch nicht fertig ,ist erstmal nur zum rumspielen

Danke im Vorraus

Flo

: Verschoben durch Admin
Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die wird nicht wegoptimiert.

Autor: Flo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also es sieht zumindes so aus ,da der Teil in der Schleife nicht 
ausgeführt wird und keine ausgabe kommt.Die stelle //uart_puts(input); 
ist im übrigen nicht auskommentiert in der Version die ich Flashe.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird, 
dann:
for(;;)
{
    __asm__ __volatile__ (""::);
}

Das geht zumindest für alle GCC. Aber am erzeugten Maschiinencode wirst 
du da kein Unterschied sehen, weil eine Schleife über nix ist immer noch 
eine Schleife über nix. Well also Oprtationen in der Schleife 
drinstehen, die keine Wirkung auf die abstrakte Maschine haben, kann 
ein Compiler diese dennoch rauswerfen.

Johann

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,

Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich 
würde das den Programmablauf unzulässig verändern.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst schrieb:
> Johann L. schrieb:
>> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,
>
> Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich
> würde das den Programmablauf unzulässig verändern.

Ja, stimmt. Aber auch bei sowas bringt es nicht unbedingt was:
for (int i=0; i < 100; i++)
{
    __asm__ __volatile__ (""::);
}

Der Compiler könne die Schleife aufrollen, und 100*nix ist eben auch 
nix...

Johann

Autor: Ingo Elsen (ogni42)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
schau mal in den Code:

schreibzeiger == lesezeiger! Damit gibt Deine checkroutine immer 0 
zurück => die if aberfrage in der for(;;) Schleife ist immer false. Und 
uart_getc wird erst innerhalb der if Abfrage ausgeführt.

EDIT: Das sei() bringt nicht viel, da Du keine ISRs zur Verfügung 
stellst.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst schrieb:
> Johann L. schrieb:
>> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,
>
> Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich
> würde das den Programmablauf unzulässig verändern.

Dadrauf bezog dein Vorposter sich mit 'Abstrakter Maschine'.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven P. schrieb:
> Stefan Ernst schrieb:
>> Johann L. schrieb:
>>> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,
>>
>> Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich
>> würde das den Programmablauf unzulässig verändern.
>
> Dadrauf bezog dein Vorposter sich mit 'Abstrakter Maschine'.

Ich verstehe nicht so ganz, was du mir damit sagen willst. Ob die 
Maschine nun abstrakt oder real ist, spielt in diesem Zusammenhang doch 
keine Rolle.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist in diesem Zusammenhang ein Begriff aus der Informatik, Thema 
Programmiersprachen und Compilerbau.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mach den Code als Dateianhang (*.c) und dann sag konkret, welche Zeile 
(Nummer) er Deiner Meinung nach wegoptimiert.

In der Regel hat er aber einen Grund, wenn er das macht. D.h. wenn Du 
ihn durch irgendetwas zwingst, es nicht zu tun, wird trotzdem nichts 
anderes passieren.

Es sei denn, es ist ein volatile-Fehler. Die kann man einfach mit der 
Optimierung -O0 rauskriegen.


Peter

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das hier
volatile uint8_t* lesezeiger; 
volatile uint8_t* schreibzeiger; 

sollte zumindest lauten
uint8_t* volatile lesezeiger; 
uint8_t* volatile schreibzeiger; 

damit sich der Compiler bei
...
if(schreibzeiger!=lesezeiger)
...

nicht mit Registerversionen der Pointer zufrieden gibt, die längst 
obsolet sind, weil sie in der ISR verändert wurden.

In Summe solltest du allerdings beides volatile machen: Die Pointer, als 
auch das, worauf die Pointer zeigen:
volatile uint8_t* volatile lesezeiger; 
volatile uint8_t* volatile schreibzeiger; 

Was ist mit der ISR? Wird sie aufgerufen (sprich: kriegst du das Echo 
von dort)? Hast du das gegengechecked, also zb ein anderes Echo 
zurückschicken; Nicht dass du einem lokalen Echo deines Terminals 
aufsitzt.

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> Johann L. schrieb:
>>> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,
>>
>> Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich
>> würde das den Programmablauf unzulässig verändern.

habt ihr gelesen was der Originalposter will?

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Sowohl der Pointer selbst, als auch das worauf er zeigt, müssen volatile
>sein.
das glaube ich jetzt erst Mal nicht, zumindest hat das nichts mit dem 
Problem zu tun

wird die ISR überhaupt ausgeführt?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Walter schrieb:

> das glaube ich jetzt erst Mal nicht, zumindest hat das nichts mit dem
> Problem zu tun

Denke schon, denn der Compiler wird uart_puffer_check() wahrscheinlich 
inlinen und dann feststellen, dass diese Funktion aufgrund seiner 
Kenntnis der Werte der beiden Pointer stets 0 zurück gibt.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Walter schrieb:
>>Sowohl der Pointer selbst, als auch das worauf er zeigt, müssen volatile
>>sein.
> das glaube ich jetzt erst Mal nicht, zumindest hat das nichts mit dem
> Problem zu tun

Ach.
Und was denkst du, wird passieren, wenn sich der Compiler
    if(uart_puffer_check()==1)

...

uint8_t uart_puffer_check(void)
{ 
if(schreibzeiger!=lesezeiger) 
  return 1; 
else return 0; 
} 


dafür entscheidet, die Pointer nicht neu aus dem Speicher zu holen, 
sondern mit Registerversionen derselben den uart_puffer_check 
durchzuführen.
Das kommt dann besonders gut, wenn die ISR (so sie überhaupt aufgerufen 
wird) die Speicherversionen der Pointer verändert, die Überprüfung aber 
mit Registerversionen stattfindet :-)

Variablen, die aus einer ISR heraus verändert werden, müssen volatile 
gemacht werden. schreibzeiger ist eine Variable. Sie wird in der ISR 
verändert und in main() abgefragt. Also muss man sie volatile machen. 
Die Tatsache, dass schreibzeiger ein Pointer ist, spielt dabei erst mal 
keine Rolle. Und die Syntax dafür ... siehe oben.

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mit dem bin ich ja einverstanden:
uint8_t* volatile lesezeiger;
uint8_t* volatile schreibzeiger;


aber wofür soll das sein:
volatile uint8_t* volatile lesezeiger;
volatile uint8_t* volatile schreibzeiger;

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Walter schrieb:
> mit dem bin ich ja einverstanden:
> uint8_t* volatile lesezeiger;
> uint8_t* volatile schreibzeiger;
>
>
> aber wofür soll das sein:
> volatile uint8_t* volatile lesezeiger;
> volatile uint8_t* volatile schreibzeiger;

Dann mach dich mal mit den Regeln vertraut, wie volatile (oder auch 
'const') angewendet werden.

Hinweis:
Bei Pointern ist sowohl bei const als auch bei volatile die Frage zu 
beantworten: Wer ist denn eigentlich const (bzw. volatile)? Der Pointer 
oder das worauf er zeigt? Oder vielleicht beides?

Autor: Michael G. (linuxgeek) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst schrieb:
> Johann L. schrieb:
>> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,
>
> Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich
> würde das den Programmablauf unzulässig verändern.

Richtig. Ein Compiler, der so "optimiert" waere fehlerhaft. Und das 
glaube ich hier nicht. Vielleicht hast Du ja einen Programmabsturz 
verursacht...

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael G. schrieb:
> Stefan Ernst schrieb:
>> Johann L. schrieb:
>>> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,
>>
>> Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich
>> würde das den Programmablauf unzulässig verändern.
>
> Richtig. Ein Compiler, der so "optimiert" waere fehlerhaft.

Wieso? Wenn der Programmfluß nicht an die Stelle kommt kann DCE (dead 
code elimination) auch Endlosschleifen wegwerfen.

Dann sieht man den Code nicht, der da ansonsten übersetzt werden würde. 
Aber Fehler ist das keiner.

Johann

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.