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


von fb (Gast)


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
1
     if (tmp.x.sekunden)
2
      tmp.x.sekunden--;

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

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


Hier der Sourcecode:
1
#include <avr/io.h>
2
3
typedef union
4
    {        
5
        struct
6
        {
7
            
8
      uint8_t sekunden;
9
            uint8_t minuten;
10
11
        } x;
12
    uint16_t sekmin;
13
    } zeit_t;
14
15
16
void testmich2 (zeit_t tmp) {
17
 GPIOR2 = tmp.x.sekunden;
18
}
19
20
21
void testmich (zeit_t zeit) {
22
23
zeit_t tmp;
24
25
for (;;) {
26
27
    tmp.x = zeit.x;
28
29
    testmich2(tmp);
30
    
31
  do {
32
     if (tmp.x.sekunden)
33
      tmp.x.sekunden--;
34
   else {
35
      tmp.x.sekunden = 59;
36
      tmp.x.minuten--;
37
   }
38
39
   } 
40
   
41
   while (tmp.sekmin);
42
}
43
44
}
45
46
int main (void) {
47
 zeit_t zeit;
48
49
 zeit.x.minuten = 1; 
50
 zeit.x.sekunden = 2;
51
52
 testmich(zeit);
53
}

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

von Bernhard R. (barnyhh)


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).

von fb (Gast)


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.

von Daniel (Gast)


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

von Bernhard R. (barnyhh)


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

von Stefan B. (stefan) Benutzerseite


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.

von fb (Gast)


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.
1
#include <avr/io.h>
2
3
typedef union
4
    {        
5
        struct
6
        {
7
 
8
               uint8_t minuten;       
9
      uint8_t sekunden;
10
 
11
        } x;
12
    uint16_t sekmin;
13
    } zeit_t;
14
15
16
void testmich2 (zeit_t tmp) {
17
 GPIOR2++;
18
}
19
20
void testmich (zeit_t zeit) {
21
22
zeit_t tmp;
23
24
for (uint8_t i=1;i<2;i++) {
25
26
    tmp.x = zeit.x;
27
    
28
  do {
29
30
  testmich2(tmp);
31
32
     if (tmp.x.sekunden)
33
      tmp.x.sekunden--;
34
   else {
35
      tmp.x.sekunden = 59;
36
      tmp.x.minuten--;
37
   }
38
39
   } 
40
   
41
   while (tmp.sekmin);
42
}
43
44
}
45
46
int main (void) {
47
 zeit_t zeit;
48
49
 zeit.x.minuten = 1; 
50
 zeit.x.sekunden = 2;
51
52
 GPIOR2 = 0;
53
54
 testmich(zeit);
55
56
 for (;;)
57
  asm("nop");
58
59
}

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

von fb (Gast)


Angehängte Dateien:

Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


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.

von fb (Gast)


Lesenswert?

1
00000034 <testmich2>:
2
    } zeit_t;
3
4
5
void testmich2 (zeit_t tmp) {
6
 //GPIOR2 = tmp.x.sekunden;
7
 GPIOR2++;
8
  34:  85 b3         in  r24, 0x15  ; 21
9
  36:  8f 5f         subi  r24, 0xFF  ; 255
10
  38:  85 bb         out  0x15, r24  ; 21
11
}
12
  3a:  08 95         ret
13
14
0000003c <testmich>:
15
16
void testmich (zeit_t zeit) {
17
  3c:  cf 93         push  r28
18
  3e:  df 93         push  r29
19
20
zeit_t tmp;
21
22
for (uint8_t i=1;i<2;i++) {
23
24
    tmp.x = zeit.x;
25
  40:  ec 01         movw  r28, r24
26
    
27
  do {
28
29
  testmich2(tmp);
30
  42:  ce 01         movw  r24, r28
31
  44:  f7 df         rcall  .-18       ; 0x34 <testmich2>
32
33
     if (tmp.x.sekunden)
34
  46:  cc 23         and  r28, r28
35
  48:  21 f0         breq  .+8        ; 0x52 <__SREG__+0x13>
36
      tmp.x.sekunden--;
37
  4a:  2c 2f         mov  r18, r28
38
  4c:  21 50         subi  r18, 0x01  ; 1
39
  4e:  e9 01         movw  r28, r18
40
  50:  02 c0         rjmp  .+4        ; 0x56 <__SREG__+0x17>
41
   else {
42
      tmp.x.sekunden = 59;
43
  52:  cb e3         ldi  r28, 0x3B  ; 59
44
      tmp.x.minuten--;
45
  54:  d1 50         subi  r29, 0x01  ; 1
46
   }
47
48
   } 
49
   
50
   while (tmp.sekmin);
51
  56:  20 97         sbiw  r28, 0x00  ; 0
52
  58:  a1 f7         brne  .-24       ; 0x42 <__SREG__+0x3>
53
}
54
55
}
56
  5a:  df 91         pop  r29
57
  5c:  cf 91         pop  r28
58
  5e:  08 95         ret
59
60
00000060 <main>:
61
 zeit_t zeit;
62
63
 zeit.x.minuten = 1; 
64
 zeit.x.sekunden = 2;
65
66
 GPIOR2 = 0;
67
  60:  15 ba         out  0x15, r1  ; 21
68
69
 testmich(zeit);
70
  62:  82 e0         ldi  r24, 0x02  ; 2
71
  64:  91 e0         ldi  r25, 0x01  ; 1
72
  66:  ea df         rcall  .-44       ; 0x3c <testmich>
73
74
 for (;;)
75
  asm("nop");
76
  68:  00 00         nop
77
  6a:  fe cf         rjmp  .-4        ; 0x68 <main+0x8>
78
79
0000006c <_exit>:
80
  6c:  f8 94         cli
81
82
0000006e <__stop_program>:
83
  6e:  ff cf         rjmp  .-2        ; 0x6e <__stop_program>


Sekunde und Minuten vertauscht:
1
00000034 <testmich2>:
2
    } zeit_t;
3
4
5
void testmich2 (zeit_t tmp) {
6
 //GPIOR2 = tmp.x.sekunden;
7
 GPIOR2++;
8
  34:  85 b3         in  r24, 0x15  ; 21
9
  36:  8f 5f         subi  r24, 0xFF  ; 255
10
  38:  85 bb         out  0x15, r24  ; 21
11
}
12
  3a:  08 95         ret
13
14
0000003c <testmich>:
15
16
void testmich (zeit_t zeit) {
17
  3c:  ef 92         push  r14
18
  3e:  ff 92         push  r15
19
  40:  cf 93         push  r28
20
  42:  df 93         push  r29
21
22
zeit_t tmp;
23
24
for (uint8_t i=1;i<2;i++) {
25
26
    tmp.x = zeit.x;
27
  44:  ec 01         movw  r28, r24
28
    
29
  do {
30
31
  testmich2(tmp);
32
  46:  ce 01         movw  r24, r28
33
  48:  f5 df         rcall  .-22       ; 0x34 <testmich2>
34
35
     if (tmp.x.sekunden)
36
  4a:  8d 2f         mov  r24, r29
37
  4c:  dd 23         and  r29, r29
38
  4e:  29 f0         breq  .+10       ; 0x5a <__SREG__+0x1b>
39
      tmp.x.sekunden--;
40
  50:  7e 01         movw  r14, r28
41
  52:  81 50         subi  r24, 0x01  ; 1
42
  54:  f8 2e         mov  r15, r24
43
  56:  e7 01         movw  r28, r14
44
  58:  02 c0         rjmp  .+4        ; 0x5e <__SREG__+0x1f>
45
   else {
46
      tmp.x.sekunden = 59;
47
  5a:  db e3         ldi  r29, 0x3B  ; 59
48
      tmp.x.minuten--;
49
  5c:  c1 50         subi  r28, 0x01  ; 1
50
   }
51
52
   } 
53
   
54
   while (tmp.sekmin);
55
  5e:  20 97         sbiw  r28, 0x00  ; 0
56
  60:  91 f7         brne  .-28       ; 0x46 <__SREG__+0x7>
57
}
58
59
}
60
  62:  df 91         pop  r29
61
  64:  cf 91         pop  r28
62
  66:  ff 90         pop  r15
63
  68:  ef 90         pop  r14
64
  6a:  08 95         ret
65
66
0000006c <main>:
67
 zeit_t zeit;
68
69
 zeit.x.minuten = 1; 
70
 zeit.x.sekunden = 2;
71
72
 GPIOR2 = 0;
73
  6c:  15 ba         out  0x15, r1  ; 21
74
75
 testmich(zeit);
76
  6e:  81 e0         ldi  r24, 0x01  ; 1
77
  70:  92 e0         ldi  r25, 0x02  ; 2
78
  72:  e4 df         rcall  .-56       ; 0x3c <testmich>
79
80
 for (;;)
81
  asm("nop");
82
  74:  00 00         nop
83
  76:  fe cf         rjmp  .-4        ; 0x74 <main+0x8>
84
85
00000078 <_exit>:
86
  78:  f8 94         cli
87
88
0000007a <__stop_program>:
89
  7a:  ff cf         rjmp  .-2        ; 0x7a <__stop_program>

von fb (Gast)


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.

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


Lesenswert?

Ja, ich denke auch, dass das ein Bug ist.  Der Bug liegt an dieser
Stelle im Code:
1
        mov r18,r28
2
        subi r18,lo8(-(-1))
3
        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:
1
typedef unsigned char uint8_t;
2
typedef unsigned short uint16_t;
3
4
typedef union
5
{
6
  struct {
7
    uint8_t sekunden;
8
    uint8_t minuten;
9
  } x;
10
  uint16_t sekmin;
11
} zeit_t;
12
13
14
void testmich2 (zeit_t tmp) {
15
  // just something that cannot be optimized out
16
  asm volatile("nop");
17
}
18
19
void testmich (zeit_t zeit) {
20
21
  zeit_t tmp;
22
23
  tmp.x = zeit.x;
24
25
  do {
26
    testmich2(tmp);
27
28
    if (tmp.x.sekunden)
29
      tmp.x.sekunden--;
30
    else {
31
      tmp.x.sekunden = 59;
32
      tmp.x.minuten--;
33
    }
34
  } while (tmp.x.sekunden || tmp.x.minuten);
35
}
36
37
int main (void) {
38
  zeit_t zeit;
39
40
  zeit.x.minuten = 1;
41
  zeit.x.sekunden = 2;
42
43
  testmich(zeit);
44
45
  return 0;
46
}

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:
1
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.

von fb (Gast)


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.

von fb (Gast)


Lesenswert?

Hi Jörg,

ok, habe eine Anleitung gefunden.
Danke nochmal.

Meine andere Frage (bzgl Account) bleibt bestehen.

lg,
Frank

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


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.

von fb (Gast)


Lesenswert?

Danke Dir !

Die Bug-Nr ist : 41894

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

lg,
Frank

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


Lesenswert?

fb schrieb:

> Die Bug-Nr ist : 41894

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

von fb (Gast)


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.

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


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.

von fb (Gast)


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

von Peter D. (peda)


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

von fb (Gast)


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 ;-)

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


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.

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


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

von fb (Gast)


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.

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


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. ;-)

von fb (Gast)


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/015_c_strukturen_009.htm

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.

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.