Forum: Compiler & IDEs For-Loop wird nicht richtig ausgeführt


von Sepp (Gast)


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

von Erwin (Gast)


Lesenswert?

Das hört sich so an, als wenn die For-Schleife leer ist. Poste doch mal 
den gesamten Code.

von (prx) A. K. (prx)


Lesenswert?

Der Compiler hat gewisse Freiheiten, unsinnigen Code rauszuwerfen. Nennt 
sich Optimierung. Eine leere for-loop mit einer normalen Variablen ist 
sowas.

Wenn du Wert drauf legst, dass jeder scheinbare Unsinn mit einer 
Variablen drin bleibt, dann mach sie volatile.

von Andreas B. (Gast)


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.

von Johann L. (gjlayde) Benutzerseite


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.

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.