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


von Daniel (Gast)


Lesenswert?

Hi,
ich hab folgenden Code, AVR Studio 4, AVR GCC, keine Warnings, keine 
Errors:
1
unsigned char USART_Receive( void )
2
{
3
  TCCR0 =(1<<WGM01) |(1<<CS01);
4
     OCR0=200;
5
  TIMSK|=(1<<OCIE0);
6
  _delay_ms(1);
7
  timeout=0;
8
9
  /* Wait for data to be received */
10
  while ( (!(UCSR1A & (1<<RXC1))) && (timeout<50) )
11
  ;
12
  TCCR0 = 0;
13
  if(timeout > 50)
14
    return ~ack;
15
  /* Get and return received data from buffer */
16
  return UDR1;
17
}
18
19
void setRelais(unsigned char adress, unsigned char value)
20
{
21
  unsigned char temp;
22
  unsigned char i=0;
23
24
  USART_Transmit(ADRESSBIT|adress);
25
  _delay_ms(10);
26
  USART_Transmit(REL_CMD_SET);
27
  _delay_ms(10);
28
  USART_Transmit(value);
29
  _delay_ms(10);
30
  USART_Transmit(ack);
31
  
32
  while(i<5) {
33
  
34
    if(USART_Receive() == ack)
35
      i=6;
36
    else {
37
      i++;
38
      USART_Transmit(ADRESSBIT|adress);
39
      _delay_ms(1);
40
      USART_Transmit(REL_CMD_SET);
41
      _delay_ms(1);
42
      USART_Transmit(value);
43
      _delay_ms(1);
44
      USART_Transmit(ack);
45
    }
46
  }
47
  ack++;
48
}
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
1
while ( (!(UCSR1A & (1<<RXC1))) && (timeout<50) )
2
  ;
 hängen.
Könntet ihr mir helfen? Irgendwo muss ich Mist gebaut haben - aber ich 
steh auf dem Schlauch :(

 Viele Grüße
 Daniel

von Daniel (Gast)


Lesenswert?

verdammt, falsches Forum.
Tut mir leid, war keine Absicht :(

 - Daniel

von Oliver (Gast)


Lesenswert?

volatile

Oliver

von J. K. (rooot)


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.

von Manuel A. (Firma: Fraunhofer IIS) (hed)


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

von Daniel (Gast)


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

von Daniel (Gast)


Lesenswert?

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

von Daniel (Gast)


Lesenswert?

Es klappt! Danke euch zwei! :-)

von J. K. (rooot)


Lesenswert?

was war's jetzt genau?

von Stefan E. (sternst)


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.

von tuppes (Gast)


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.

von Karl H. (kbuchegg)


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
1
   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'

von Johann L. (gjlayde) Benutzerseite


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

von Karl H. (kbuchegg)


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.

von ein (Gast)


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.

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


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.

von ein (Gast)


Lesenswert?

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

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


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.

von Johann L. (gjlayde) Benutzerseite


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

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.