Forum: Compiler & IDEs zählt diese for Schleife 10mal?


von Martin (Gast)


Lesenswert?

Hallo,

ich beschäftige mich gerade mit den Schleifentypen.

Diese for-Schleife sollte doch 10mal durchlaufen werden?

Blockiert die for-schleife bei einem Thread auch alles, so wie die while 
schleife?
1
for(wi=0; wi=9; wi++)
2
{
3
4
}


Gruß Martin

von for-next (Gast)


Lesenswert?

nein!

von MaWin (Gast)


Lesenswert?

> Diese for-Schleife sollte doch 10mal durchlaufen werden?

Nein, natürlich nicht.
Du solltest noch mal Zuweisung und Vergleich nachschlagen.

> Blockiert die for-schleife bei einem Thread auch alles,
> so wie die while schleife?

Sie ist wie die while-Schleife, aber ob's blockiert liegt
an dir.

von for (Gast)


Lesenswert?

Martin schrieb:
> Diese for-Schleife sollte doch 10mal durchlaufen werden?

Nein, es gibt einen Unterschied zwischen "=" und "==".

von Florian (Gast)


Lesenswert?

Auch mit == wirds nicht gehen.

An den Fragesteller: Lies nochmal nach, was der mittlere Ausdruck (dein 
wi=9) steuert.

von Timmo H. (masterfx)


Lesenswert?

for schrieb:
> Nein, es gibt einen Unterschied zwischen "=" und "==".
zumal hier ein "<" oder "<=" angebracht wäre

von DirkB (Gast)


Lesenswert?

Die for-Schleife wird solange durchlaufen, wie die Bedingung (in der 
Mitte) wahr ist.

Da du am Anfang schon wi auf 0 setzt, ist die Bedingung (auch wenn du 
sie mit == schreibst) falsch.

Darum for(wi=0; wi<10; wi++) und du kannst sehen, dass sie 10 mal 
durchlaufen wird.

von g457 (Gast)


Lesenswert?

> Diese for-Schleife sollte doch 10mal durchlaufen werden?

Nope, dasdas

> for(wi=0; wi=9; wi++)

ist eine Endlosschleife.

HTH

von Tilo (Gast)


Lesenswert?

Wieso sollte das eine Endlosschleife sein?

von Sam .. (sam1994)


Lesenswert?

wi=9 ist immer wahr

von Klaus W. (mfgkw)


Lesenswert?

Weil der Ausdruck immer wahr ist.

von g457 (Gast)


Lesenswert?

> Wieso sollte das eine Endlosschleife sein?

Weil 'wi=9' in

> for(wi=0; wi=9; wi++)

immer [1] zu wahr auswertet (und des TOs Schleifenkörper ziemlich leer 
ist).

HTH

[1] ich setzt jetzt mal einen Integertyp voraus für wi. In C++ kann man 
da natürlich Sauereien anstellen..

von Peter D. (peda)


Lesenswert?

Ich schreibe immer die Anzahl als erster Ausdruck, das ist am besten 
lesbar. Auch kennen die Compiler diese Schreibweise und optimeren das 
sehr gut, z.B. zu DJNZ beim 8051.
1
for( i = 10; i; i-- ){
2
...
3
}


Peter

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:
> Auch kennen die Compiler diese Schreibweise und optimeren
> das sehr gut, ...

Es gibt Compiler, die anhand der "Schreibweise" optimieren?

von Rolf M. (rmagnus)


Lesenswert?

Sie erkennen die aus dieser Schreibweise resultierende Kombination aus 
Dekrementierung und einem Vergleich mit 0. Da in der Regel das Dekrement 
auch schon die Flags setzt, kann man die Vergleichs-Instruktion 
weglassen, und das tun die Compiler dann auch.

von Heinz (Gast)


Lesenswert?

Da es sich hier offensichtlich um eine kopfgesteuerte Schleife handelt, 
die nur für ehem. Basic-user von K&R eingerichtet wurde, könnte man auf 
die Idee kommen, dieses for() Konstrukt für sich über den Haufen zu 
werfen und im Sinne einer while-Schleife zu kodieren. Es ist ja nix 
anderes als das. Dann gäbe es auch nicht so viele Fragen hier im Forum 
über die korrekte Schreibweise dieser Parameter.
Also: (ich bin nur Pascal-Programmierer)
1
laufvar = 0;
2
while (laufvar <[=] ende {
3
4
  laufvar++;
5
}
Ich finde, dass das einfach übersichtlicher ist.
In Pascal schreibe ich:
1
laufvar := 0;
2
while (laufvar <[=] ende) then
3
  begin
4
    ...
5
    inc(Lauvar);
6
  end;
Ich habe beides(for.. und while(mit vorheriger Initalisierung der 
Laufvariablen)) in einem C-Programm versucht. Das generierte Hex-File 
war in beiden Fällen gleich groß.

von Nico S. (nico22)


Lesenswert?

Johann L. schrieb:
> Peter Dannegger schrieb:
>> Auch kennen die Compiler diese Schreibweise und optimeren
>> das sehr gut, ...
>
> Es gibt Compiler, die anhand der "Schreibweise" optimieren?

Ich wollte diese Aussage selbst tatsächlich auch nicht glauben. Daher 
hier mal harte Fakten (gcc (Gentoo 4.5.3-r1 p1.0, pie-0.4.5) 4.5.3)

Ohne Optimierung:
1
int main(void) {
2
   0:  55                     push   %rbp
3
   1:  48 89 e5               mov    %rsp,%rbp
4
5
        int i;
6
7
        for(i = 0; i < 50; i++) {
8
   4:  c7 45 fc 00 00 00 00   movl   $0x0,-0x4(%rbp)
9
   b:  eb 04                  jmp    11 <main+0x11>
10
   d:  83 45 fc 01            addl   $0x1,-0x4(%rbp)
11
  11:  83 7d fc 31            cmpl   $0x31,-0x4(%rbp)
12
  15:  7e f6                  jle    d <main+0xd>
13
    asm("":::"memory");
14
        }
15
16
        for(i = 50; i; i--) {
17
  17:  c7 45 fc 32 00 00 00   movl   $0x32,-0x4(%rbp)
18
  1e:  eb 04                  jmp    24 <main+0x24>
19
  20:  83 6d fc 01            subl   $0x1,-0x4(%rbp)
20
  24:  83 7d fc 00            cmpl   $0x0,-0x4(%rbp)
21
  28:  75 f6                  jne    20 <main+0x20>
22
    asm("":::"memory");
23
        }
24
25
        return 0;
26
  2a:  b8 00 00 00 00         mov    $0x0,%eax
27
}
28
  2f:  c9                     leaveq 
29
  30:  c3                     retq

Hah! Zu früh gefreut. Schon mit O2 hingegen macht es wirklich einen 
Unterschied:
1
int main(void) {
2
   0:  b8 32 00 00 00         mov    $0x32,%eax
3
   5:  0f 1f 00               nopl   (%rax)
4
5
        int i;
6
7
        for(i = 0; i < 50; i++) {
8
   8:  83 e8 01               sub    $0x1,%eax
9
   b:  75 fb                  jne    8 <main+0x8>
10
   d:  b8 32 00 00 00         mov    $0x32,%eax
11
  12:  66 0f 1f 44 00 00      nopw   0x0(%rax,%rax,1)
12
    asm("":::"memory");
13
        }
14
15
        for(i = 50; i; i--) {
16
  18:  83 e8 01               sub    $0x1,%eax
17
  1b:  75 fb                  jne    18 <main+0x18>
18
    asm("":::"memory");
19
        }
20
21
        return 0;
22
}
23
  1d:  31 c0                  xor    %eax,%eax
24
  1f:  c3                     retq

Da das mov/nopw aber ja schon zur zweiten Schleife gehört, ist es doch 
wieder ohne Unterschied :-/

von Heinz (Gast)


Lesenswert?

Nico Sch. schrieb:
> Das hätte ich nicht erwartet.
Du hast das mit einem Compiler for x86 getestet. Kannst du meine o.a. 
Idee auch noch mal verifizieren? Müsste sonst Turbo C wieder aus dem 
Grab holen :-)

von MaWin (Gast)


Lesenswert?

> dieses for() Konstrukt für sich über den Haufen zu
> werfen und im Sinne einer while-Schleife zu kodieren.

Könnte man.

Man könnte auch GOTOs einbauen, wenn man
strukturiertes Programmieren nicht versteht.

von Heinz (Gast)


Lesenswert?

MaWin schrieb:
> Man könnte auch GOTOs einbauen, wenn man
> strukturiertes Programmieren nicht versteht.
Sei nicht so streng. War ja nur als Hilfe für die gedacht, die es bis 
heute nicht verstanden haben :-).

von Nico S. (nico22)


Lesenswert?

@Heinz:
1
  0:  b8 32 00 00 00         mov    $0x32,%eax
2
   5:  0f 1f 00               nopl   (%rax)
3
4
        int i = 0;
5
6
  while(i < 50) {
7
   8:  83 e8 01               sub    $0x1,%eax
8
   b:  75 fb                  jne    8 <main+0x8>
9
    asm("":::"memory");
10
    i++;
11
  }

Also wieder mov, nop*, sub und jne. Tut sich nichts. O2.

von Heinz (Gast)


Lesenswert?

Danke dir, Nico!

von Andreas B. (andreas_b77)


Lesenswert?

Ob das Zählen aufwärts oder abwärts unterschiedlich optimiert werden 
kann, hängt grundsätzlich vom Code in der Schleife ab. Der Compiler kann 
zwar bei konstanten Bedingungen erkennen, wie viele Durchläufe es gibt 
und dementsprechend optimieren.

Das hilft aber nichts, wenn der Code in der Schleife den Zähler 
undurchsichtig verwendet, denn dann muss der Compiler sich 
standardkonform verhalten. Bei "i=0; i<50; i++" heißt das, das zuerst 
i=0 ausgeführt wird, dann i=1, dann i=2, ... Und das 
"asm("":::"memory");"  verhindert jede Optimierung, denn es schreibt 
vor, dass alle Werte von Variablen vorher davor in ihre Speicherstellen 
geschrieben werden und danach wieder geladen werden (da sie sich 
verändert haben könnten). Damit wird wieder eine Sequentialisierung 
erzwungen.

Wenn man das nicht erzwingt, kann der Compiler das sehr wohl umformen:
1
void g(void);
2
3
void f(void)
4
{
5
  int i;
6
7
  for (i = 0; i < 50; i++)
8
    g();
9
}

Hier die Ausgabe vom gcc für ARM mit -O2:
1
00000000 <f>:
2
   0:  e92d4010   push  {r4, lr}
3
   4:  e3a04032   mov  r4, #50  ; 0x32
4
   8:  ebfffffe   bl  0 <g>
5
   c:  e2544001   subs  r4, r4, #1
6
  10:  1afffffc   bne  8 <f+0x8>
7
  14:  e8bd4010   pop  {r4, lr}
8
  18:  e12fff1e   bx  lr

Man sieht, er zählt abwärts und nutzt das Zero Flag statt einem extra 
Vergleich.

von Andreas B. (andreas_b77)


Lesenswert?

Oder in 3 Varianten:
1
void g(void);
2
3
void f(void)
4
{
5
  int i;
6
7
  for (i = 0; i < 50; i++)
8
    g();
9
10
  for (i = 50; i > 0; i--)
11
    g();
12
13
  for (i = 100; i < 200; i += 2)
14
    g();
15
}

Dieses Mal als gcc -S Ausgabe:
1
f:
2
  @ Function supports interworking.
3
  @ args = 0, pretend = 0, frame = 0
4
  @ frame_needed = 0, uses_anonymous_args = 0
5
  stmfd  sp!, {r4, lr}
6
  mov  r4, #50
7
.L2:
8
  bl  g
9
  subs  r4, r4, #1
10
  bne  .L2
11
  mov  r4, #50
12
.L3:
13
  bl  g
14
  subs  r4, r4, #1
15
  bne  .L3
16
  mov  r4, #50
17
.L4:
18
  bl  g
19
  subs  r4, r4, #1
20
  bne  .L4
21
  ldmfd  sp!, {r4, lr}
22
  bx  lr

Und wenn er noch die Inhalte der Schleifen vergleichen würde, könnte er 
das alles in eine Schleife packen… Aber das wird in realem Code wohl so 
selten auftreten, dass sich eine solche Optimierung nicht lohnt.

von Karl H. (kbuchegg)


Lesenswert?

Heinz schrieb:
> Da es sich hier offensichtlich um eine kopfgesteuerte Schleife handelt,
> die nur für ehem. Basic-user von K&R eingerichtet wurde,

Äh, nein.

Der Sinn der Sache in C war es, das 'Pattern'

  Initialisierung;
  while( Bedingung ) {
    Statement;
    Increment;
  }

so zu formulieren, dass die für die Schleifensteuerung wesentlichen 
Teile (Initialisierung, Bedingung und Increment) an EINER Stelle 
beisammen bleiben und nicht quer über den Code verstreut werden. Eben

  for( Initialisierung; Bedingung; Increment )
    Statement

Das hat also ganz handfeste softwaretechnische Gründe und mit Basic 
schon gleich gar nichts zu tun. For-Schleifen in Basic funktionieren 
ganz anders und zb in Fortran (wo das DO-Schleife heißt) wieder anders. 
Lass dich nicht vom Schlüsselwort blenden! Nur weil Dinge in 
verschiedenen Sprachen dasselbe Schlüsselwort benutzen, heißt das nicht, 
dass die Funktionalität identisch ist.

> die Idee kommen, dieses for() Konstrukt für sich über den Haufen zu
> werfen und im Sinne einer while-Schleife zu kodieren. Es ist ja nix
> anderes als das.

Richtig. Könnte man

> Dann gäbe es auch nicht so viele Fragen hier im Forum
> über die korrekte Schreibweise dieser Parameter.

Ist aber trotzdem der falsche Ansatz.
for hat schon seinen Sinn. Das man in der Lernphase mal Fehler macht ist 
nichts neues und auch nicht ungewöhnlich. Deswegen ist es aber nicht 
zielführend Dinge links liegen zu lassen. Nächstens kommst du dann mit 
"Da Funktionen so kompliziert sind kann man auch den Funktionscode 
direkt an der Aufrufstelle einsetzen. Ist ja im Prinzip auch nichts 
anderes."

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.