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?
> 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.
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.
> 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..
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.
Peter Dannegger schrieb:> Auch kennen die Compiler diese Schreibweise und optimeren> das sehr gut, ...
Es gibt Compiler, die anhand der "Schreibweise" optimieren?
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.
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ß.
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 :-/
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 :-)
> 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.
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 :-).
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:
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.
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."