mikrocontroller.net

Forum: Compiler & IDEs GCC Optimierer macht Code funktionsuntüchtig


Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
ich hab folgenden Code, AVR Studio 4, AVR GCC, keine Warnings, keine 
Errors:
unsigned char USART_Receive( void )
{
  TCCR0 =(1<<WGM01) |(1<<CS01);
     OCR0=200;
  TIMSK|=(1<<OCIE0);
  _delay_ms(1);
  timeout=0;

  /* Wait for data to be received */
  while ( (!(UCSR1A & (1<<RXC1))) && (timeout<50) )
  ;
  TCCR0 = 0;
  if(timeout > 50)
    return ~ack;
  /* Get and return received data from buffer */
  return UDR1;
}

void setRelais(unsigned char adress, unsigned char value)
{
  unsigned char temp;
  unsigned char i=0;

  USART_Transmit(ADRESSBIT|adress);
  _delay_ms(10);
  USART_Transmit(REL_CMD_SET);
  _delay_ms(10);
  USART_Transmit(value);
  _delay_ms(10);
  USART_Transmit(ack);
  
  while(i<5) {
  
    if(USART_Receive() == ack)
      i=6;
    else {
      i++;
      USART_Transmit(ADRESSBIT|adress);
      _delay_ms(1);
      USART_Transmit(REL_CMD_SET);
      _delay_ms(1);
      USART_Transmit(value);
      _delay_ms(1);
      USART_Transmit(ack);
    }
  }
  ack++;
}
timeout wird in einem Interrupt erhöht.

Mit keiner Optimierung läuft der Code.
Mit Optimierung -Os (Standard in AVR Studio),
läuft der Code nicht, er bleibt irgendwie/wo
an
while ( (!(UCSR1A & (1<<RXC1))) && (timeout<50) )
  ;
 hängen.
Könntet ihr mir helfen? Irgendwo muss ich Mist gebaut haben - aber ich 
steh auf dem Schlauch :(

 Viele Grüße
 Daniel

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
verdammt, falsches Forum.
Tut mir leid, war keine Absicht :(

 - Daniel

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
volatile

Oliver

Autor: J. K. (rooot)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vollständiger code?

meine glaskugel sagt mir aber, dass du  timeout  nicht volatile gesetzt 
hast http://www.imb-jena.de/~gmueller/kurse/c_c++/c_volat.html

mfg
J.K.

Autor: Manuel Andreu (Firma: Fraunhofer IIS) (hed)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Meiner Meinung nach ist das

while ( (!(UCSR1A & (1<<RXC1))) && (timeout<50) );

so nicht richtig.

In C/C++ ist && ein lazy and, das bedeuted, dass die zweite Bedingung 
nur geprüft wird wenn die erste true ist.

Falls du kein Zeichen empfängst ist die erste Bedingung immer false, 
daher wird nie auf den Timeout geprüft.

Richtig sollte es heißen:

while ((timeout<50) && (!(UCSR1A & (1<<RXC1))));

Das ganze passiert nur bei aktivierter Optimierung, da der Compiler erst 
dann das lazy and nutzt.

mfg Manuel

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der ganze Code ist etwas lang, aber deine Glaskugel hat vollkommen
recht und klingt auch sehr plausibel. Werde ich gleich mal testen :)
Vielen, vielen Dank

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und auch danke Manuel,
das wusste ich noch gar nicht, aber auch das klingt schonmal nach einem
Grund! :-)

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es klappt! Danke euch zwei! :-)

Autor: J. K. (rooot)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
was war's jetzt genau?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manuel Andreu schrieb:

> Meiner Meinung nach ist das
>
> while ( (!(UCSR1A & (1<<RXC1))) && (timeout<50) );
>
> so nicht richtig.
>
> In C/C++ ist && ein lazy and, das bedeuted, dass die zweite Bedingung
> nur geprüft wird wenn die erste true ist.
>
> Falls du kein Zeichen empfängst ist die erste Bedingung immer false,
> daher wird nie auf den Timeout geprüft.

Nein, sie ist dann immer true, und timeout wird zum entscheidenden 
Faktor, so wie es auch gedacht ist.

> Richtig sollte es heißen:
>
> while ((timeout<50) && (!(UCSR1A & (1<<RXC1))));

Das Tauschen der beiden &&-Operanten hat hier keinerlei Auswirkungen. 
Beide Varianten sind richtig. Das Problem wird ein fehlendes volatile 
sein.

Autor: tuppes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manuel Andreu:
> In C/C++ ist && ein lazy and, das bedeuted,
> dass die zweite Bedingung nur geprüft wird
> wenn die erste true ist.

So weit stimmts.

> Das ganze passiert nur bei aktivierter Optimierung,
> da der Compiler erst dann das lazy and nutzt.

Das stimmt nicht. && ist immer lazy, auch ohne Optimierung.

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

Bewertung
0 lesenswert
nicht lesenswert
tuppes schrieb:
> Manuel Andreu:
>> In C/C++ ist && ein lazy and, das bedeuted,
>> dass die zweite Bedingung nur geprüft wird
>> wenn die erste true ist.
>
> So weit stimmts.
>
>> Das ganze passiert nur bei aktivierter Optimierung,
>> da der Compiler erst dann das lazy and nutzt.
>
> Das stimmt nicht. && ist immer lazy, auch ohne Optimierung.

Noch ein kleiner Nachtrag:
... und das ist auch wichtig, dass das so ist. Letztendlich garantiert 
mir dieses geforderte Verhalten, dass eine Abfrage
   if( Pointer && Pointer->Member )

die NULL-Pointer Behandlung korrekt ausführt und keinen ungültigen 
Member-Zugriff nach sich zieht. In anderen Sprachen, zb Ur-Pascal, war 
das nicht so und hat unnötig tief verschachtelten Code nach sich 
gezogen.

PS2: Der Ausdruck 'lazy' ist dafür in C/C++ unüblich. Man spricht hier 
meist von 'shortcut evaluation'

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tuppes schrieb:

>> Das ganze passiert nur bei aktivierter Optimierung,
>> da der Compiler erst dann das lazy and nutzt.
>
> Das stimmt nicht. && ist immer lazy, auch ohne Optimierung.

Ich hab gcc schon Code erzeugen gesehen, wo er die zweite Bedinung 
auswertete, obwohl die erste falsch war. Erst dachte ich an nen Bug, 
aber es war nur in Fällen, wo kein Speicherzugriff erfolgte; es ging um 
reine Arithmetik und die Maschine verfügte über Befehle, die (A' & B') 
für bestimmt Ausdrücke A' und B' effizient auswerten konnte, und die die 
gleichen Effekte auf die Maschine hatten, als (A && B), wobei A und A' 
bzw. B und B' in bestimmten Zusammenhang standen.

Womöglich erkennte die Analyse, daß B unabhängig von A war.

Es war aber in allen Fällen so, daß der Code korrekt war und was auf der 
Maschine abging nicht der C-Semantik widersprach.

Johann

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

Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:

> Es war aber in allen Fällen so, daß der Code korrekt war und was auf der
> Maschine abging nicht der C-Semantik widersprach.

Tja. Das ist schwer zu beurteilen ohne den konkreten Code und die 
konkrete Maschine. Mgwl. hat der Optimizer rausgefunden, dass die 
Evaluierung billiger ist, als eine Abfrage samt conditional Branch samt 
eventuellem Pipeline Reloading.

Rein formal muss der Compiler aber bei einem && den 2-ten Ausdruck 
unausgewertet lassen, wenn der erste bereits falsch ist.

Und dann gibts natürlich noch die 'As-if' Regel. Der Optimizer darf den 
Code umstricken wie er lustig ist, solange sich das Ergebnis so verhält, 
'as-if' der Optimizer nie am Werke war. Dass der gcc bei dem von dir 
beobachteten Fällen einen Fehler gemacht hat, glaub ich nicht wirklich. 
Solche Shortcuts werden oft ausgenutzt, sodass man auf fehlerhaftes 
Verhalten schnell aufmerksam werden würde. Auf der anderen Seite machen 
Optimizer heutzutage Analysen, die sollte man nicht für möglich halten.

Autor: ein (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich mag da nicht mehr up to date sein, aber früher hat der Standard dem 
Compiler die Entscheidung überlassen, in welcher Reihenfolge die Zweige 
von logischen Verknüpfungen überprüft werden und ob alle Zweige 
überprüft werden oder nur die nötigen. Da war das geschilderte Verhalten 
lediglich das spezifische Verhalten von gcc, nicht unbedingt von allen 
Compilern.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ein schrieb:
> Ich mag da nicht mehr up to date sein, aber früher hat der Standard dem
> Compiler die Entscheidung überlassen, in welcher Reihenfolge die Zweige
> von logischen Verknüpfungen überprüft werden und ob alle Zweige
> überprüft werden oder nur die nötigen.

Nein, in C war das schon immer definiert.

Autor: ein (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie's aussieht, hab ich das in der Erinnerung wohl mit den 
Funktionsparametern verwechselt. Operatoren haben in der Tat eine 
definierte Assoziativität.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ein schrieb:
> Operatoren haben in der Tat eine
> definierte Assoziativität.

Es geht hier nicht um die Assoziativität, sondern ausdrücklich
darum, dass die Argumente von && und || von links nach rechts
dergestalt bewertet werden müssen, dass die Evaluierung des
Ausdrucks abgebrochen wird, sowie sein logisches Ergebnis
eindeutig feststeht.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:

> Und dann gibts natürlich noch die 'As-if' Regel. Der Optimizer darf den
> Code umstricken wie er lustig ist, solange sich das Ergebnis so verhält,
> 'as-if' der Optimizer nie am Werke war.

Jo, der berühmte Unterschied zwischen der abstrakten Maschine und der 
realen Maschine ;-)

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.