For-Loop wird nicht richtig ausgeführt

Gast #1920249
Lesenswert?

Hallo
Habe ein Problem,wenn ich eine einfaches C-Programm im AVR Studio 4.12 
neustes update mit GCC Unterstützung simulieren will. (Habe schon in 
Assembler programmiert jedoch wenig in anderen C-Compiler)

Umgebung: windows xp, Atmel stk 500, Atiny 13

Beispiel: For loop

int an;
....
 for(an=0;an<=10;an=an+1)
.....

da sollte doch "an" um eins hochgezählt werden bis 10.
 Aber im Debugger ist die Variable beim ersten For-Schritt schon bei 11 
(elf!) (auch Im Watch Fenster) angelangt und die Schleife wird natürlich 
sofort verlassen!
Habe andere Variablen probiert wie auch z.B. andere Start und Endwerte 
verwendet.
Kann mir das nicht vorstellen

Danke für einen Hinweis
Viele Grüsse
Gast #1920266
Lesenswert?

Kommt drauf an, was in der Schleife steht. GCC kann da auch eine ganze 
Schleife wegoptimieren wenn es den Schleifeninhalt auch ohne Schleife in 
einem Rutsch ausführen kann.

Mal als Beispiel:
1
unsigned int test(unsigned int n)
2
{
3
  unsigned int x;
4

5
  for (x = n; x < n + 20; x++)
6
    ;
7

8
  return x;
9
}

Mit eingeschalteter Optimierung (-O2) wird das auf x86 zu:
1
0000000000000000 <test>:
2
   0:  89 f8                  mov    %edi,%eax
3
   2:  83 c0 14               add    $0x14,%eax
4
   5:  0f 42 c7               cmovb  %edi,%eax
5
   8:  c3                     retq

Man sieht, da wird anstatt 20 mal zu inkrementieren direkt 20 addiert.


Wenn du alles wie im Quellcode ausgeführt sehen willst, musst du die 
Optimierungen ausschalten. Mit Optimierungen wird es auch auf andere 
Weise unübersichtlich im Debugger, z.B. kann die Reihenfolge der 
Anweisungen umgestellt werden.
Persönliche Seite #1921097
Lesenswert?

Hier mal ein kleines Beispielprogramm:
1
int fac (int x)
2
{
3
    if (x == 0)
4
        return 1;
5

6
    return x * fac (x-1);
7
}
8

9
int main()
10
{
11
    return fac (7);
12
}

avr-gcc 4.5.1 bzw. 4.6.0 mit -O2 macht aus main:
1
main:
2
  ldi r24,lo8(5040)
3
  ldi r25,hi8(5040)
4
  ret

d.h. der (end-)rekursive Aufruf ist komplett verschwunden. Es wird nur 
7! ins return-reg geladen. Da die Fakultätsfunktion hier nicht-statisch 
ist, muss sie ausimplementiert werden. Das sieht für einen ATmega8 und 
auf Größe optimiert so aus:
1
fac:
2
  ldi r18,lo8(1)
3
  ldi r19,hi8(1)
4
.L3:
5
  sbiw r24,0
6
  breq .L2
7
  movw r20,r18
8
  mul r20,r24
9
  movw r18,r0
10
  mul r20,r25
11
  add r19,r0
12
  mul r21,r24
13
  add r19,r0
14
  clr r1
15
  sbiw r24,1
16
  rjmp .L3
17
.L2:
18
  movw r24,r18
19
  ret

Nix mehr mit Rekursion. gcc erzeugt eine normale Schleife.

Ergo: Der Compiler transformiert den Code so, daß er die gleiche Wirkung 
hat, aber kann das auf ganz anderen Wegen erreichen, als man anhand der 
Quelle zu glauben geneigt ist. Entsprechend verwirrend kann das Debuggen 
solchen Codes ausfallen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren