Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - For-Schleife "kaputt"?
Der Michel - Fr 14.03.03 10:10
Titel: For-Schleife "kaputt"?
Hallo,
wenn ich den folgenden Code ausführe fängt Delphi immer mit i = 20 an und zählt rückwärts. Kann mir jemand erklären woran das liegt? Ein Neustart von Delphi / Windows hat keine Abhilfe geschaffen.
Ich benutze Delphi 5.0 Professional ( Compilierung 6.18 ) mit UpdatePack1 und Windows 2000 Professional (Service Pack 2).
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm1.Button1Click(Sender: TObject); var aTmp : array[0..19] of string; i : integer; begin for i := 0 to High(aTmp) do begin if (aTmp[i] <> '') then Caption := aTmp[i]; end; end; |
Gruß,
Michel
Keldorn - Fr 14.03.03 10:24
hallo du meinst eher
Quelltext
1:
| Caption := caption+aTmp[i]; |
ansonsten hast du mit deinem Code immer das letzte Zeichen drin
Der Michel - Fr 14.03.03 10:29
Hallo,
ja das stimmt schon, ist aber in diesem Fall egal, da es mir nur darum ging dass i rückwärts gezählt wird und der Code nur ein Beispiel ist. :)
Wenn ich allerdings schreibe:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| procedure TForm1.Button1Click(Sender: TObject); var aTmp : array[0..19] of string; i : integer; begin // Nur als Beispiel, Code macht nicht wirklich Sinn for i := 0 to High(aTmp) do begin if (i = 1000) then Beep(); if (aTmp[i] <> '') then Caption := aTmp[i]; end; end; |
funktioniert alles bestens und i wird von 0 bis 19 gezählt.
Kann mir das jemand erklären?
Gruß,
Michel
Keldorn - Fr 14.03.03 10:32
äh wie kommst du darauf, das von hintengezählt wird?
wenn du einen breakpoint setzt und die Schleife das erste mal durchlaufen wird, hat i ja noch keinen wert. sezt den haltepunkt in die Schleife, da sollte es anders aussehen
Mfg Frank
Der Michel - Fr 14.03.03 10:37
Hallo,
ich hab einen Breakpoint gesetzt bei "for i := 0 ..." und bin, als der Debugger dort ankam, in die nächste Zeile gegangen, und wenn ich mit der Maus auf i gezeigt hab stand da immer "i = 20", beim nächsten Schleifendurchlauf "i = 19" usw. Obwohl es (laut Code) ja eigentlich anders sein sollte. Du kannst es ja mal in Deinem Delphi ausprobieren ob es sich da auch so verhält, vielleicht muß ich das ja nur mal neu installieren?
Gruß,
Michel
Delete - Fr 14.03.03 11:39
Hat schon alles seine Ordnung. Da ist nichts geheimnisvolles dran. Da hat die Compileroptimierung von Delphi zugeschlagen.
Wird die Schleife denn korrekt abgearbeitet? Das ist doch das entscheidende.
Der Michel - Fr 14.03.03 11:55
Hallo,
ja, letztendlich wird es korrekt abgearbeitet. Obwohl er im ersten Schleifendurchlauf zwar anzeigt daß er an eine Funktion als Parameter 'aTmp[20]' übergibt (wo natürlich nur Müll drinsteht), kommt aber tatsächlich der Wert von 'aTmp[0]' an.
Aber als mir das zum ersten Mal aufgefallen ist hab ich ganz schön sparsam geguckt. :wink:
Gruß,
Michel
Klabautermann - Fr 14.03.03 12:15
Hi,
ich mus Luckie zustimmen. Das wird an der Optimierung liegen. Bei deinem ersen Beispiel "erkennt" Delphi das es kein unterschied macht, ob die Schleife vorwärts oder rückwärts gezählt wird. Also lässt er sie rückwärts laufen, weil das schneller ist (im Assembler kann man nur auf 0 abfragen also mus Delphi beim hochzahlen immer das ergebnis einer Rechnung überprüfen, die 0 ergibt wenn die obere Grenze erreicht wurde beim runterzählen kann direckt auf 0 geprüft werden).
Ich deinem zweiten Beispiel reicht die "intelligenz" des Compilers einfach nicht mehr aus, um das ganze zu durchschauen.
Gruß
Klabutermann
Der Michel - Fr 14.03.03 12:39
Hallo,
klingt einleuchtend.
Beim Auftreten des nächsten mysteriösen Phänomens weiß ich dann Bescheid. ;-)
Besten Dank.
Gruß,
Michel
Wolff68 - Fr 14.03.03 20:28
Das mit der Code-Optimierung stimmt zwar, und Delphi zählt dann gerne mal rückwärts. ABER: Eben in diesem Beispiel ist es eben NICHT Egal, ob vorwärts, oder rückwärts gezählt wird.
IF Tmp[i] <> '' then Caption := Tmp[i]
Daraus folgt, daß Du nach dem Durchlauf der Schleife den letzten, nicht leeren Eintrag im Caption stehen haben möchtest! Und nicht den ersten! Denn genau den bekommst Du angezeigt, wenn die Schleife runterzählt.
Also sollte sie Code-Optimierung in diesem Beispiel erkennen, daß es eben NICHT egal ist, ob hoch- oder runtergezählt wird.
Erkennt sie das nicht, würde das ganze bei mir schon unter die Rubrik BUG fallen.
Popov - Fr 14.03.03 20:45
Jajn. Eigentlich schon. Andererseits auch nicht. Wenn es wichtig wäre, dann brächte man es nicht über eine Schleife zu jagen. Alos nicht so:
For ... To ... Do IF Tmp[i] <> '' then Caption := Tmp[i]
sondern so
Caption := Tmp[High(aTmp)]
Wenn also das eine wenig Sinn ergibt, wieso soll es dann einen Sinn ergeben den letzten Array zuzuweisen.
Wolff68 - Fr 14.03.03 21:40
Beispiel Tmp = ['','1','2','3','4','','','','8','','']
Dann wäre:
Tmp[High(Tmp)] = ''
For...to...If...<>'' ... = '8' (Wenn hochgezählt)
For...downto...If...<>'' = '1' (Wenn runtergezählt)
Oder seh ich das falsch?
Popov - Fr 14.03.03 21:58
Du siehst das nicht falsch. Allerdings ist es nicht so, als ob man hier einen bestimmten Wert eines Arrays haben wollte:
Quelltext
1: 2: 3: 4:
| for i := 0 to High(aTmp) do begin if (aTmp[i] <> '') then Caption := aTmp[i]; end; |
Zugegeben, es soll der letzte nicht leere Wert sein. Aber anschinend ist es nicht so wichtig - denkt sich der Compiler.
Wenn ich mich erinnere, so hab ich auch mal das Problem gehabt. Ich glaube dammals hab ich das entweder per Inc gemacht oder per x - i.
Wolff68 - Fr 14.03.03 22:25
Egal was der Compiler denkt; Ich finde es schon wichtig, ob ich in meiner Steuererklärung nachher '1' oder '8' stehen hab...
Aber um hier mal die Gemüter zu beruhigen:
Ich hab das Beispiel mal nachgebaut und aTmp[2] := '2' und aTmp[8] := 8; mit eingefügt. (Damit im Array auch was drin ist)
Er zählt zwar i nun immer noch rückwärts, aber stellt das intern so um, daß doch das richtige rauskommt. :shock:
Ist echt lustig, wenn er plötzlich bei i = 18 dem Label eine '2' zuweist, und bei i = 12 kommt dann die 8 :lol:
Probiert es mal aus. Hier der Code:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TForm1.Button1Click(Sender: TObject); var aTmp : Array[0..19] of String; i : Integer; begin Label1.Caption := ''; aTmp[2] := '2'; aTmp[8] := '8'; for i := 0 to High(aTmp) do begin if (aTmp[i] <> '') then Label1.Caption := aTmp[i]; end; end; |
AndyB - Sa 15.03.03 00:30
| Wolff68 hat folgendes geschrieben: |
| Er zählt zwar i nun immer noch rückwärts |
Falsch. Die Schleife wird vorwärts durchlaufen. Den Link, den ich gepostet habe, habt ihr beide nicht angeschaut.
Der Compiler stellt den Code dahingehend um, dass der Zeiger auf das Array bei jedem Durchlauf auf das nächste Element zeigt. Um nun aber das Schleifenende zu ermitteln wird (aus Geschwindigkeitsgründen) eine Variable bis auf 0 heruntergezählt. Da der Debugger den Array-Zeiger schlecht anzeigen kann, nimmt er eben die erst beste Variable, und die wird eben auf 0 heruntergezählt.
Quelltext
1: 2: 3: 4: 5: 6: 7:
| var MyArray: array[0..100] of Integer; Index: Integer; begin for Index := 0 to 100 do MyArray[Index] := 10; end; |
Daraus mach der Compiler das:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| var MyArray: array[0..100] of Integer; Counter: Integer; // liegt auf der selben Speicheradresse wie "Index" HelperArray: PInteger; // ist in einem CPU Register ausgelagert begin HelperArray := @MyArray[0]; for Counter := 100 downto 0 do begin HelperArray^ := 10; Inc(HelperArray); // Zeiger auf das nächste Array-Element end; end; |
Wer ein Programm debuggt, sollte zuerst die Code-Optimierung ausschalten.
Brueggendiek - Sa 15.03.03 01:11
Hallo!
| AndyB hat folgendes geschrieben: |
| Wer ein Programm debuggt, sollte zuerst die Code-Optimierung ausschalten. |
Das ist schon deshalb wichtig, weil man sonst beim Debugger-Zugriff auf lokale Variablen gelegentlich bekommmt: "kann wegen Optimierung nicht zugegriffen werden" - der Compiler hat erkannt, daß die Variable nicht mehr benötigt wird und sie vorzeitig gelöscht. Ärgerlich, wenn ich nach einer Schleife mit 1000 Durchläufen den auf Result zugewiesenen Wert lesen will, ihn nicht mehr kriege und das Funktionsergebnis gleich weiterverarbeitet wird!
Gruß
Dietmar Brüggendiek
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!