mikrocontroller.net

Forum: Compiler & IDEs Bug in WinAVR oder liegts an mir?


Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich habe lange nach einem Fehler bei mir gesucht,
aber mir scheint, avr-gcc (WinAVR 20090313) 4.3.2) macht es falsch.

Ich habe den Fehler mit einem kurzen Programmstück provozieren können 
(s.u)

Das Stück
     if (tmp.x.sekunden)
      tmp.x.sekunden--;

wird falsch übersetzt - oder jedenfalls funktioniert es nicht so, wie es 
soll, denn beim Decrement läuft was falsch.
  do {
     if (tmp.x.sekunden)
  4c:  cc 23         and  r28, r28
  4e:  21 f0         breq  .+8        ; 0x58 <__SREG__+0x19>
      tmp.x.sekunden--;
  50:  2c 2f         mov  r18, r28
  52:  21 50         subi  r18, 0x01  ; 1
  54:  e9 01         movw  r28, r18 
  56:  02 c0         rjmp  .+4        ; 0x5c <__SREG__+0x1d>
   else {
      tmp.x.sekunden = 59;
  58:  cb e3         ldi  r28, 0x3B  ; 59
      tmp.x.minuten--;
  5a:  d1 50         subi  r29, 0x01  ; 1
   }

Wie kommt das  movw r28, r18 dorthin ?
Übrigens funktioniert es wenn man in der Union Sekunden und Minuten 
vertauscht.


Hier der Sourcecode:
#include <avr/io.h>

typedef union
    {        
        struct
        {
            
      uint8_t sekunden;
            uint8_t minuten;

        } x;
    uint16_t sekmin;
    } zeit_t;


void testmich2 (zeit_t tmp) {
 GPIOR2 = tmp.x.sekunden;
}


void testmich (zeit_t zeit) {

zeit_t tmp;

for (;;) {

    tmp.x = zeit.x;

    testmich2(tmp);
    
  do {
     if (tmp.x.sekunden)
      tmp.x.sekunden--;
   else {
      tmp.x.sekunden = 59;
      tmp.x.minuten--;
   }

   } 
   
   while (tmp.sekmin);
}

}

int main (void) {
 zeit_t zeit;

 zeit.x.minuten = 1; 
 zeit.x.sekunden = 2;

 testmich(zeit);
}

Aufruf :
avr-gcc -c -mmcu=attiny2313 -I. -gdwarf-2 -DF_CPU=8000000UL -Os 
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall 
-Wstrict-prototypes -mshort-calls -Wa,-adhlns=./bug.lst  -std=gnu99 
-fno-inline-small-functions -finline-limit=3 --param
inline-call-cost=2 -fno-if-conversion -fno-split-wide-types 
-fno-tree-scev-cprop -MMD -MP -MF .dep/bug.o.d bug.c -o bug.o



Woran liegts ?
Ist das tatsächlich ein Bug, oder ist etwas anderes schuld ?
Hab ich was falsch gemacht ??

mfg,
 Frank

Autor: Bernhard R. (barnyhh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Frank,
der Compiler hat nicht ganz konsequent optimiert!

Die Schleife
    do { ... } while (tmp.sekmin);
läßt sich ersetzen durch

    tmp.sekmin = 0;

Das hat der Compiler "natürlich" nicht erkannt, aber er hat eins 
erkannt:
tmp.x.minuten wird durcgh die do-Schleife auf 0 gesetzt.

Genau das hat er generiert.

Bernhard

P.S. Der Fehler sitzt üblicherweise vor dem Bildschirm (des 
Anwendungsprogrammierers, nicht des Compilerbauers).

Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Bernhard,

wie ich schrieb, ist das Beispiel konstruiert, im echten Programm 
passiert in der Schleife viel mehr.
Ist aber auch egal, denn in testmich2() schreibt er in GPIOR, und das 
ist darf nicht wegoptimiert werden (ist glaube ich volatile).

Die Anzahl der Schleifendurchläufe stimmt so nicht. Egal ob er nun was 
berechtigterweise was wegoptimiert nicht... das sieht man besser, wenn 
in testmich2 z.b. eine Ausgabe auf LCD erfolgt. das mit GPIO ist auch 
nur ein Beispiel um einen kurzen Testcode zu bekommen.

Außerdem ist das keine Erklärung dafür, daß es funktioniert, wenn man in 
der Union Sekunden und Minuten vertauscht...

So richtig überzeugt mich Deine Erklärung noch nicht :-)
Lasse mich aber trotzdem immernoch gerne vom Gegenteil überzeugen.

lg,
Frank.

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Frank,

Bernhard hat mit seiner Aussage recht:
---
Die Schleife
  do { ... } while (tmp.sekmin);
läßt sich ersetzen durch
  tmp.sekmin = 0;
---

Die Abbruchbedingung der Schleife hängt ja nicht von veränderlichen 
Eingangsgrößen ab und enthält keine volatile-Zugriffe. Das Ergebnis der 
Schleife ist hier immer konstant.
Die Anzahl der Schleifendurchläufe ändert ebenfalls nichts am Ergebnis.
Das Register GPIOR wird ebenfalls nicht angetastet.

Bevor du einen Compilerfehler suchst, kompiliere testweise mal
mit Option -O0 statt -Os oder verwende volatile für tmp.


Grüße
Daniel

Autor: Bernhard R. (barnyhh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Frank,

die do-Schleife führt genau folgendes aus (Pseudocode):

Do until tmp.x.sekunden == 0 and tmp.x.minuten == 0
    Wenn tmp.x.sekunden != 0 dann
        tmp.x.sekunden = tmp.x.sekunden - 1
    sonst
        tmp.x.sekunden = 59
        tmp.x.minuten = tmp.x.minuten - 1
    Ende Wenn
Ende Do

Diese Schleife tut nichts anderes als tmp.x.sekunden und tmp.x.minuten 
geordnet herunterzuzählen, bis beide null sind. Dann terminiert sie. 
Probiere es händisch aus.

Für den Compiler spielt es keine Rolle, was an Code produziert wird, 
solange der generierte Code genau das tut, was er lt. source-code tun 
soll. Und das ist hier mit ziemlicher Sicherheit der Fall.

Leider fehlt in dem Code-Schnipsel die Initialisierung von r19. Selbiges 
dürfte in der Initialisierung auf 0 gelöscht worden sein, um 
tmp.x.minuten auf 0 zu setzen.

Bernhard

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
fb schrieb:

> Wie kommt das  movw r28, r18 dorthin ?

Der verminderte Wert aus R18 (und das unveränderte R19) wird zurück in 
die struct bei R28 (und R29) geschrieben. Das MOV ist schonmal OK.

Ob das MOVW (d.h. der nicht sichtbare R19->R29 Teil) ein Fehler ist, 
kann man an deinem Codefetzen nicht sehen.

Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, schande auf mein Haupt, ihr habt Recht :-)

Für den oben geposteten Code stimmen Eure Argumente tatsächlich.

Habe den Code geändert (s.u.)

Tut mir mal torrtzdem den Gefallen, und probiert das im Debugger. Bitte 
:-)
Setzt mal einen Breakpoint auf den NOP.

Ergebnis: GPIOR2 ist dort 0x02.

Jetzt vertauschen wir in der Union die Zeilen für Minuten und Sekunden 
(also wirklich nur die Reihenfolge), und lassen das Programm nochmal 
laufen.

Ergebnis: GPIOR2 ist 0x3E

Frage: Warum ?

Apropos Codefetzen: Bevor man sich die Mühe macht hier rumzupesten 
sollte man das Ding mal eben durch den Compiler jagen und selbst 
sehen... oder nach nach einem gößerem Ausschnitt fragen.
#include <avr/io.h>

typedef union
    {        
        struct
        {
 
               uint8_t minuten;       
      uint8_t sekunden;
 
        } x;
    uint16_t sekmin;
    } zeit_t;


void testmich2 (zeit_t tmp) {
 GPIOR2++;
}

void testmich (zeit_t zeit) {

zeit_t tmp;

for (uint8_t i=1;i<2;i++) {

    tmp.x = zeit.x;
    
  do {

  testmich2(tmp);

     if (tmp.x.sekunden)
      tmp.x.sekunden--;
   else {
      tmp.x.sekunden = 59;
      tmp.x.minuten--;
   }

   } 
   
   while (tmp.sekmin);
}

}

int main (void) {
 zeit_t zeit;

 zeit.x.minuten = 1; 
 zeit.x.sekunden = 2;

 GPIOR2 = 0;

 testmich(zeit);

 for (;;)
  asm("nop");

}


Bei Bedarf kann ich auch die vollständigen LSS-Dateien beider Versionen 
posten...

Autor: fb (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hier das Makefile.
Benutzt bitte dieses.
Wie ich grade feststelle, hängt es wohl mit den Compileroptionen 
zusammen.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, ich bin da raus, nicht weil ich gleich ins Kino (TROPA DE ELITE) 
gehe ;-) sondern weil ich ein älteres WinAVR einsetze. Der ASM-Code von 
dem Stück oben sah bei mir schon ganz anders aus.

Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

00000034 <testmich2>:
    } zeit_t;


void testmich2 (zeit_t tmp) {
 //GPIOR2 = tmp.x.sekunden;
 GPIOR2++;
  34:  85 b3         in  r24, 0x15  ; 21
  36:  8f 5f         subi  r24, 0xFF  ; 255
  38:  85 bb         out  0x15, r24  ; 21
}
  3a:  08 95         ret

0000003c <testmich>:

void testmich (zeit_t zeit) {
  3c:  cf 93         push  r28
  3e:  df 93         push  r29

zeit_t tmp;

for (uint8_t i=1;i<2;i++) {

    tmp.x = zeit.x;
  40:  ec 01         movw  r28, r24
    
  do {

  testmich2(tmp);
  42:  ce 01         movw  r24, r28
  44:  f7 df         rcall  .-18       ; 0x34 <testmich2>

     if (tmp.x.sekunden)
  46:  cc 23         and  r28, r28
  48:  21 f0         breq  .+8        ; 0x52 <__SREG__+0x13>
      tmp.x.sekunden--;
  4a:  2c 2f         mov  r18, r28
  4c:  21 50         subi  r18, 0x01  ; 1
  4e:  e9 01         movw  r28, r18
  50:  02 c0         rjmp  .+4        ; 0x56 <__SREG__+0x17>
   else {
      tmp.x.sekunden = 59;
  52:  cb e3         ldi  r28, 0x3B  ; 59
      tmp.x.minuten--;
  54:  d1 50         subi  r29, 0x01  ; 1
   }

   } 
   
   while (tmp.sekmin);
  56:  20 97         sbiw  r28, 0x00  ; 0
  58:  a1 f7         brne  .-24       ; 0x42 <__SREG__+0x3>
}

}
  5a:  df 91         pop  r29
  5c:  cf 91         pop  r28
  5e:  08 95         ret

00000060 <main>:
 zeit_t zeit;

 zeit.x.minuten = 1; 
 zeit.x.sekunden = 2;

 GPIOR2 = 0;
  60:  15 ba         out  0x15, r1  ; 21

 testmich(zeit);
  62:  82 e0         ldi  r24, 0x02  ; 2
  64:  91 e0         ldi  r25, 0x01  ; 1
  66:  ea df         rcall  .-44       ; 0x3c <testmich>

 for (;;)
  asm("nop");
  68:  00 00         nop
  6a:  fe cf         rjmp  .-4        ; 0x68 <main+0x8>

0000006c <_exit>:
  6c:  f8 94         cli

0000006e <__stop_program>:
  6e:  ff cf         rjmp  .-2        ; 0x6e <__stop_program>



Sekunde und Minuten vertauscht:

00000034 <testmich2>:
    } zeit_t;


void testmich2 (zeit_t tmp) {
 //GPIOR2 = tmp.x.sekunden;
 GPIOR2++;
  34:  85 b3         in  r24, 0x15  ; 21
  36:  8f 5f         subi  r24, 0xFF  ; 255
  38:  85 bb         out  0x15, r24  ; 21
}
  3a:  08 95         ret

0000003c <testmich>:

void testmich (zeit_t zeit) {
  3c:  ef 92         push  r14
  3e:  ff 92         push  r15
  40:  cf 93         push  r28
  42:  df 93         push  r29

zeit_t tmp;

for (uint8_t i=1;i<2;i++) {

    tmp.x = zeit.x;
  44:  ec 01         movw  r28, r24
    
  do {

  testmich2(tmp);
  46:  ce 01         movw  r24, r28
  48:  f5 df         rcall  .-22       ; 0x34 <testmich2>

     if (tmp.x.sekunden)
  4a:  8d 2f         mov  r24, r29
  4c:  dd 23         and  r29, r29
  4e:  29 f0         breq  .+10       ; 0x5a <__SREG__+0x1b>
      tmp.x.sekunden--;
  50:  7e 01         movw  r14, r28
  52:  81 50         subi  r24, 0x01  ; 1
  54:  f8 2e         mov  r15, r24
  56:  e7 01         movw  r28, r14
  58:  02 c0         rjmp  .+4        ; 0x5e <__SREG__+0x1f>
   else {
      tmp.x.sekunden = 59;
  5a:  db e3         ldi  r29, 0x3B  ; 59
      tmp.x.minuten--;
  5c:  c1 50         subi  r28, 0x01  ; 1
   }

   } 
   
   while (tmp.sekmin);
  5e:  20 97         sbiw  r28, 0x00  ; 0
  60:  91 f7         brne  .-28       ; 0x46 <__SREG__+0x7>
}

}
  62:  df 91         pop  r29
  64:  cf 91         pop  r28
  66:  ff 90         pop  r15
  68:  ef 90         pop  r14
  6a:  08 95         ret

0000006c <main>:
 zeit_t zeit;

 zeit.x.minuten = 1; 
 zeit.x.sekunden = 2;

 GPIOR2 = 0;
  6c:  15 ba         out  0x15, r1  ; 21

 testmich(zeit);
  6e:  81 e0         ldi  r24, 0x01  ; 1
  70:  92 e0         ldi  r25, 0x02  ; 2
  72:  e4 df         rcall  .-56       ; 0x3c <testmich>

 for (;;)
  asm("nop");
  74:  00 00         nop
  76:  fe cf         rjmp  .-4        ; 0x74 <main+0x8>

00000078 <_exit>:
  78:  f8 94         cli

0000007a <__stop_program>:
  7a:  ff cf         rjmp  .-2        ; 0x7a <__stop_program>


Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok... falls es jemanden interessieren sollte:

Es liegt an den beliebten Schaltern

-finline-limit=3 --param inline-call-cost=2

Warum auch immer.
Läßt man sie weg, funktioniert das Programm.

Da scheint ganz schön was im Argen zu sein...
Leider kann ich es nicht genauer eingrenzen, meine Möglichkeiten sind 
damit erschöpft.


P.s. Darf ich jetzt davon ausgehen, daß es NICHT mein Fehler ist, oder
übersehe ich immer noch was ?
Die Schalter dürfen doch keinesfalls zu falschem Code führen.

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

Bewertung
0 lesenswert
nicht lesenswert
Ja, ich denke auch, dass das ein Bug ist.  Der Bug liegt an dieser
Stelle im Code:
        mov r18,r28
        subi r18,lo8(-(-1))
        movw r28,r18

Warum auch immer, der Compiler schiebt für die Subtraktion von
tmp.x.sekunde den Wert nach r18.  Anschließend benutzt er aber
eine Wortoperation, um ihn wieder nach tmp zurück zu speichern.
Dabei wird das (undefiniert gesetzte und offenbar auf 0 stehende)
Register r19 nach r29 kopiert, sodass das komplette tmp.x dann
auf { .minute = 0, .sekunde = 1 } steht.  Danach bedarf es noch
eines einzelnen Schleifendurchlaufs, und alles wird beendet.

Ich habe dein Beispiel mal auf folgendes runtergebrochen, was
offenbar das Minimalbeispiel darstellt:
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;

typedef union
{
  struct {
    uint8_t sekunden;
    uint8_t minuten;
  } x;
  uint16_t sekmin;
} zeit_t;


void testmich2 (zeit_t tmp) {
  // just something that cannot be optimized out
  asm volatile("nop");
}

void testmich (zeit_t zeit) {

  zeit_t tmp;

  tmp.x = zeit.x;

  do {
    testmich2(tmp);

    if (tmp.x.sekunden)
      tmp.x.sekunden--;
    else {
      tmp.x.sekunden = 59;
      tmp.x.minuten--;
    }
  } while (tmp.x.sekunden || tmp.x.minuten);
}

int main (void) {
  zeit_t zeit;

  zeit.x.minuten = 1;
  zeit.x.sekunden = 2;

  testmich(zeit);

  return 0;
}

Dieses Beispiel kannst du direkt in einem GCC-Bugreport benutzen, da
es keinerlei Abhängigkeiten mehr von einer konkreten AVR-Maschine
oder anderweitig vom Präprozessor besitzt, d. h. das sieht nach dem
Präprozessor immer noch genauso aus.  Außerdem vermeidet es das
potenziell undefinierte Verhalten als Ursache, dass du in einer
union verschiedene Teile beschreibst und dann ausliest.

Außerdem habe ich die Kommandozeile auf folgendes Minimum herunter
gebrochen:
avr-gcc -S -mmcu=atmega128 -Os -fno-inline-small-functions -fno-split-wide-types bug.c

Offenbar liegt der Bug also darin, wie das -fno-split-wide-types
implementiert ist und ist aber nur reproduzierbar, wenn man das
inlining von testmich2() verhindert.

Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Jörg,
ok, wenn Du mir verrätst wie das geht ? :-)

Achso, und da du Mod bist:
Ich habe hier auch einen Account, lange nicht benutzt, habe aber 
inzwischen mein Passwort vergessen und meine eMail-Addy hat sich 
geändert; kann man da was machen ?

Übrigens hatte ich damals auch schon in einem Thread auf einen Bug 
hingewiesen. Der ist inwischen gefixt. :-)

lg,
Frank.

Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Jörg,

ok, habe eine Anleitung gefunden.
Danke nochmal.

Meine andere Frage (bzgl Account) bleibt bestehen.

lg,
Frank

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

Bewertung
0 lesenswert
nicht lesenswert
fb schrieb:

> ok, wenn Du mir verrätst wie das geht ? :-)

Du tippst "gcc bug reporting" bei Tante Gugel ein, und kannst
eigentlich "Auf gut Glück!" drücken, denn der erste Link ist:

http://gcc.gnu.org/bugs/

> Achso, und da du Mod bist:

...aber ich bin nicht Andreas. ;-)  Schreib' ihm eine Mail.  Adresse
findest du im Impressum.

Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Dir !

Die Bug-Nr ist : 41894

Ich hoffe alles richtig gemacht zu haben..kenne mich mit der Thematik 
nicht aus.

lg,
Frank

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

Bewertung
0 lesenswert
nicht lesenswert
fb schrieb:

> Die Bug-Nr ist : 41894

Wie du siehst, zieht das ja schon die ersten Blasen. ;-)

Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jo :-)

wollte grade die verlangte .S Datei hochladen, da machte mein Outlook 
"Ding" und jemand anderes ;-) war schon schneller.

Was meinst Du, ist der Bug was AVR-Spezifisches, oder kann das auch 
andere Targets treffen ?

Danke.
Frank.

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

Bewertung
0 lesenswert
nicht lesenswert
fb schrieb:

> Was meinst Du, ist der Bug was AVR-Spezifisches, oder kann das auch
> andere Targets treffen ?

Das ist so schwer zu sagen.  Da Andy Hutchinson schon drauf aufmerksam
geworden ist, vermute ich mal, dass er sich zumindest zu einer Analyse
aufraffen wird.

Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine letzte kleine Bitte noch :-)

Könnte einer der Mods bitte den Thread-Titel ändern ?
Mein halb editiertes Gestammel ist ja peinlich... :-)

lg,
Frank

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Offenbar liegt der Bug also darin, wie das -fno-split-wide-types
> implementiert ist und ist aber nur reproduzierbar, wenn man das
> inlining von testmich2() verhindert.

Mir ist auch schon aufgefallen, daß -fno-split-wide-types den Code eines 
gesamten Programms optimiert, aber bei einzelnen Funktionen mehr Code 
erzeugt.
In der Regel verringert es aber deutlich die Zahl unnötiger MOVs.


Der Befehl MOVW wurde ja erst später von Atmel implementiert.
Es könnte also eine Art Copy&Paste Fehler sein, wo an einer Stelle 
zuviel das MOV durch MOVW ersetzt wurde.


Peter

Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andy Hutchinson scheint an der Sache dran zu sein.

Ich habe da noch eine Frage :

Ich schreibe in Sekmin einen Wert, und lese später x.Sekunden und 
x.Minuten.
Ist das undefiniertes Verhalten ?

Falls nein, kann ich evtl noch einen Bugreport hinterherschieben...

Habe grade das Phänomen, daß (laut ASM-Listing) zwar sekmin geschrieben 
wird, aber später anstelle von x.sekunden einfach 0 benutzt wird ?!?
:confused:

Derzeit macht er das aber nur in meinem "großem" Programm, das ich hier 
niemandem zumuten möchte ;-)

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

Bewertung
0 lesenswert
nicht lesenswert
fb schrieb:

> Ich schreibe in Sekmin einen Wert, und lese später x.Sekunden und
> x.Minuten.
> Ist das undefiniertes Verhalten ?

Ich habe keine klare Aussage im Standard dazu gefunden, aber ich
denke schon -- schon deshalb, weil zwischen sek und min ja noch
padding sein könnte.

> Habe grade das Phänomen, daß (laut ASM-Listing) zwar sekmin geschrieben
> wird, aber später anstelle von x.sekunden einfach 0 benutzt wird ?!?

Wenn der Standard das nicht sanktioniert, dass man tatsächlich eine
union über verschiedene Pfade zugreifen kann, dann kann ich mir gut
vorstellen, dass der Compiler das halt optimieren darf, so nach dem
Motto: unionname.x.sek wurde nur mit 0 beschrieben, mehr hat sich
seither nicht geändert, also ist er noch 0.

Daher hatte ich dein Fehlerbeispiel auch so geändert, dass es auf
der sicheren Seite bezüglich des Standards liegt.

Es könnte noch sein, dass das von dir beschriebene Verhalten sich
durch -fno-strict-aliasing abändern lässt.  Kannst dir ja mal die
Beschreibung zu -fstrict-aliasing in der GCC-Dokumentation durchlesen.

Ich wäre mittlerweile mit derartigen "historischen Missbräuchen"
recht vorsichtig.  Es gibt meistens elegantere Methoden, das zu
lösen, und all dein Herum-Aliasen zwischen sekmin und sek/min ist
eine derartige Mikrooptimierung, dass ich nicht glaube, dass davon
die Benutzbarkeit deines Programms irgendwie abhängt.  Ich würde das
einfach sein lassen und Minuten und Sekunden ganz normal separat
handhaben.

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

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:

> Es könnte also eine Art Copy&Paste Fehler sein, wo an einer Stelle
> zuviel das MOV durch MOVW ersetzt wurde.

:-)

Peter, ich mag Andy Hutchinsons Analyse hier nicht posten, weil die
Erklärung doch recht umfangreich ist.  Schau einfach mal selbst rein,
damit du ein Gefühl bekommst, um welche Art Fehler es sich so
handelt...

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41894

Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe da was gefunden, einen Ausschnitt aus der avr/eeprom.h :

    union
    {
        uint16_t word;
        struct
        {
            uint8_t lo;
            uint8_t hi;
        } byte;
    } x;

    x.word = __value;
    eeprom_write_byte ((uint8_t *)__p, x.byte.lo);
    eeprom_write_byte ((uint8_t *)__p + 1, x.byte.hi);

Jetzt gibts 2 Möglichkeiten:

Entweder das ist erlaubt, oder die eeprom.h funktioniert nur rein 
zufällig.

Bei mir funktionierts nicht. Übertragen auf obiges Beispiel würde bei 
mir immer eine 0 ins eeprom Geschrieben. Allerdings kann ich diese 
"Erscheinung" derzeit aus Zeitgründen (noch) nicht erfolgreich auf ein 
(kleines) Testprogramm runterbrechen.... zischen "x.word = __value;" und 
dem lesen passiert bei mir noch eine ganze Menge. Evtl liegts daran.
Oder an mir ;-)

Ich bleib dran.

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

Bewertung
0 lesenswert
nicht lesenswert
fb schrieb:

> Entweder das ist erlaubt, oder die eeprom.h funktioniert nur rein
> zufällig.

Die <avr/eeprom.h> würde ich als Bestandteil der "implementation" im
Sinne des C-Standards sehen, denn die avr-libc (zu der sie gehört)
bildet ja den Teil der Standarbibliothek für die AVR-GCC-Implemen-
tierung.

Damit steht es dieser Datei frei, sich auf internes Verhalten des
Compilers zu verlassen, sofern es mit allen funktionierenden GCC-
Versionen funktioniert.  Das kann ja durchaus gegeben sein, auch
wenn das entsprechende Verhalten vom Standard als undefiniert gilt.

Allerdings hätte die avr-libc ein Problem, falls sich das Compiler-
verhalten mal ändert, dann müsste man diese Stelle anfassen.

Wenn dich die Details interessieren, was bei unions tatsächlich vom
Standard abgedeckt wird und als portabel gelten kann, dann frage mal
in der Newsgruppe de.comp.lang.c nach.  Dort sitzen die Sprach-
Rechtsanwälte der Sprache C. ;-)

Autor: fb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok.. einverstanden..
Das ist wohl etwas Glatteis, auf das sich die libc da begibt, aber 
solange es funktioniert.. :-)

Übrigens steht hier, dass es tatsächlich undefiniert ist:
http://openbook.galileocomputing.de/c_von_a_bis_z/...

Hab mein Programm geändert und verzichte auf die Union. Damit gehe ich 
dann auch dem Bug oben aus dem Weg.

Nochmal Danke !

lg,
Frank.

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.