Autor Beitrag
Tobi482
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 135



BeitragVerfasst: So 05.10.08 11:40 
hi Leute,

heute hat es Delphi wieder einmal geschafft mich total zuverwirren. Es scheint, als ob Schleifendruchgänge des Schleifenkörpers einfach nicht ausgeführt werden.

Ich möchte eine Datei nach speziellen Squenzen von Zeichen durchsuchen. Daher lese ich die ganze Datei in einen Buffer ein und kontrolliere jedes Zeichen, ob es der Anfang einer gesuchten Sequenz ist.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
procedure Tmain.btn_scanClick(Sender: TObject);
var
     pData          : Pointer;
     hFile          : Integer;
     Size           : Cardinal;
     i,j            : Cardinal;
begin
     //Datei auswählen
     if not od.Execute then exit;

     //Datei öffnen
     hFile := FileOpen(od.FileName, fmOpenReadWrite);
     if hFile = -1 then
     begin
          Addlog('Fehler beim öffnen der Datei');
          Exit;
     end;

     //Dateigröße ermittelm
     Size := GetFileSizeEx(od.FileName);

     //Speicher reservieren
     pData := GetMemory(Size);

     //Daten einlesen
     FileRead(hFile, pData^, Size);

     //Jedes Zeichen druchgehen
     j := 0;
     for i := 0 to Size-255-1 do
     begin
          if isSequenceOffset(Ptr(Cardinal(pData)+i)) then
          begin
               j := j + 1;
               Addlog('Sequenz gefunden bei ' + IntToHex(i, 8));
          end;

          if i mod 1000 = 0 then
          begin
               main.Caption := FloatToStr(i/size*100);
          end;
     end;
     Addlog(IntToStr(j) + ' Sequenzen gefunden');

     //Datei schließen
     FileClose(hFile);

     //Speicher freigeben
     FreeMemory(pData);
end;


Einige Dateien sind sehr groß, und das suchen dauert sehr lange. Daher habe ich einen Prozentanzeige in den Fensternnamen gepackt. Würde ich diese Anzeige bei jedem Durchlauf refreshen ist dies eine große Performance-Bremse. Daher lasse ich die Caption nur alle 1000 Schleifendruchläufe aktualisieren.

Soweit sogut^^

Zur Probe habe ich eine Datei mit 1000 der gesuchten Squenzen erzeugt. Davon werden jedoch nur 16 gefunden.

JETZT KOMMT DER HAMMER.

Stelle ich die mod-Zeile "if i mod 1000 = 0 then" auf "if i mod 500 = 0 then" werden 233 gefunden. Mit "if i mod 100 = 0 then" werden 532 gefunden und bei "mod 1" alle.

BITTE WAS?
WIE WO WAS WARUM?

Wie kann diese Zeile den Ablauf derart beeinflussen?

Mit freundlichen Grüßen
Tobi
GTA-Place
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
EE-Regisseur
Beiträge: 5248
Erhaltene Danke: 2

WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
BeitragVerfasst: So 05.10.08 11:54 
Ruf Application.ProcessMessages; auf, bevor du die Daten in ein Log einträgst.

_________________
"Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
Tobi482 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 135



BeitragVerfasst: So 05.10.08 11:59 
Wenn die Zeilen nicht angezeigt werden sollten, dann müsste doch aber die Anzahl in j stimmen.
Leider funktioniert auch diese Code "nicht". Wenn man mod verändert werden jeweils mehr Sequenzen gefunden.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
procedure Tmain.btn_scanClick(Sender: TObject);
var
     pData          : Pointer;
     hFile          : Integer;
     Size           : Cardinal;
     i,j            : Cardinal;
begin
     //Datei auswählen
     if not od.Execute then exit;
     Application.ProcessMessages;

     //Datei öffnen
     hFile := FileOpen(od.FileName, fmOpenReadWrite);
     Application.ProcessMessages;
     if hFile = -1 then
     begin
          Addlog('Fehler beim öffnen der Datei');
          Exit;
     end;

     //Dateigröße ermittelm
     Size := GetFileSizeEx(od.FileName);
     Application.ProcessMessages;

     //SPeicher reservieren
     pData := GetMemory(Size);
     Application.ProcessMessages;

     //Daten einlesen
     FileRead(hFile, pData^, Size);
     Application.ProcessMessages;

     //Jedes Zeichen druchgehen
     j := 0;
     for i := 0 to Size-255-1 do
     begin
          if isSequenceOffset(Ptr(Cardinal(pData)+i)) then
          begin
               Application.ProcessMessages;
               j := j + 1;
               Application.ProcessMessages;
               Addlog('Sequenz gefunden bei ' + IntToHex(i, 8));
               Application.ProcessMessages
          end;
          Application.ProcessMessages;

          if i mod 1000 = 0 then
          begin
               main.Caption := FloatToStr(i/size*100);
               Application.ProcessMessages;
          end;
          Application.ProcessMessages;

     end;
     Addlog(IntToStr(j) + ' Sequenzen gefunden');
     Application.ProcessMessages;

     //Datei schließen
     FileClose(hFile);
     Application.ProcessMessages;

     //SPeicher freigeben
     FreeMemory(pData);
     Application.ProcessMessages;
end;



Gruß Tobi
Hidden
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2242
Erhaltene Danke: 55

Win10
VS Code, Delphi 2010 Prof.
BeitragVerfasst: So 05.10.08 12:18 
Hi,

Du kannst dein Suchfenster aber meißtens um mehr als eins verschieben ;) Da lässt sich noch sehr viel optimieren.

Aber warum verwendest du nicht einfach die vordefinierte Funktion "Pos"? Die ist wahrscheinlich um das zig-fache schneller und du brauchst deine ProgressBar vielleicht garnicht.

ausblenden Delphi-Quelltext
1:
  function Pos(const Keyword, S: String): Integer;					

Wenn der Teilstring nicht enthalten ist, ist der Rückgabewert null.

mfG,

_________________
Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 05.10.08 12:26 
user profile iconHidden hat folgendes geschrieben Zum zitierten Posting springen:
Aber warum verwendest du nicht einfach die vordefinierte Funktion "Pos"? Die ist wahrscheinlich um das zig-fache schneller und du brauchst deine ProgressBar vielleicht garnicht.
Das dürfte bei sehr großen Dateien trotzdem lange dauern. ;-) // EDIT: --> Wie wäre es mit Threads? Oder was user profile iconHidden vermutlich auch meinte: Boyer-Moore?

user profile iconTobi482 hat folgendes geschrieben Zum zitierten Posting springen:
Wie kann diese Zeile den Ablauf derart beeinflussen?
Bei solchen "unerklärlichen" Fehlern würde ich mal vermuten, dass du da irgendwo auf falsche Speicherbereiche zugreifst bzw. diese überschreibst, was dann solche Effekte hat. (Ich habs mir jetzt nicht genauer angeschaut.)
Tobi482 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 135



BeitragVerfasst: So 05.10.08 12:32 
Pos funktioniert nur, wenn die Sequenze durch reguläre ausdrücke darstellbar ist. Mein ausdruck wäre aber sehr sehr lang (reg exp = 255 verschieden Zeichen hintereinander). aber ich habe noch was cooles herrausgefunden

Dieser Code findet alles Squenzen
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
     //Jedes Zeichen druchgehen
     j := 0;
     for i := 0 to Size-255-1 do
     begin

          if isSequnceOffset(Ptr(Cardinal(pData)+i)) then
          begin
               j := j + 1;
               Addlog('Sequenz gefunden bei ' + IntToHex(i, 8));
          end;

          main.Caption := 'a';
     end;
     Addlog(IntToStr(j) + ' Sequenzen gefunden');



Dieser Code findet keine Squenz
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
     //Jedes Zeichen druchgehen
     j := 0;
     for i := 0 to Size-255-1 do
     begin

          if isSequnceOffset(Ptr(Cardinal(pData)+i)) then
          begin
               j := j + 1;
               Addlog('Sequenz gefunden bei ' + IntToHex(i, 8));
          end;

          //main.Caption := 'a';
     end;
     Addlog(IntToStr(j) + ' Sequenzen gefunden');


Nun bin ihc völlig verwirrt, was zum Teufel hat meine Frame main damit am hut?

Gruß
Tobi
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 05.10.08 12:34 
Wie gesagt: Du überschreibst irgendwo den falschen Speicher, das muss nicht an dieser Stelle passieren, sondern irgendwo im Code. Typisch dafür ist, dass die Effekte beim Zugriff auf VCL-Komponenten passieren, denn die reagieren eben allergisch darauf.
Tobi482 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 135



BeitragVerfasst: So 05.10.08 12:38 
Code funktioniert nicht
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
     AssignFile(f, '.\c.ini');
     Rewrite(f);

     //Jedes Zeichen druchgehen
     j := 0;
     for i := 0 to Size-255-1 do
     begin

          if isSequenceOffset(Ptr(Cardinal(pData)+i)) then
          begin
               j := j + 1;
               Addlog('Sequenz gefunden bei ' + IntToHex(i, 8));
          end;

          //Writeln(f, inttostr(i));
     end;
     Addlog(IntToStr(j) + ' Sequenzen gefunden');

     closefile(f);


Code funktioniert
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
     AssignFile(f, '.\c.ini');
     Rewrite(f);

     //Jedes Zeichen druchgehen
     j := 0;
     for i := 0 to Size-255-1 do
     begin

          if isSequenceOffset(Ptr(Cardinal(pData)+i)) then
          begin
               j := j + 1;
               Addlog('Sequenz gefunden bei ' + IntToHex(i, 8));
          end;

          Writeln(f, inttostr(i));
     end;
     Addlog(IntToStr(j) + ' Sequenzen gefunden');

     closefile(f);


AHHH DELPHI IST VERRÜCKT !!!

ok wenn das so ist, wie du sagt, dass ich das irgendwas überschrieben wie umgehe ich dass, ohne "schrott" in meine funktion zu bauen?

Gruß
Tobi
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 05.10.08 12:39 
Den Fehler finden ;-).
Wobei ich jetzt deinen aktuellen Code nicht genauer nach Fehlern angeschaut habe.
Hidden
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2242
Erhaltene Danke: 55

Win10
VS Code, Delphi 2010 Prof.
BeitragVerfasst: So 05.10.08 13:05 
Hi,

Wäre schön, wenn du bei Vergleichen immer kurz die Unterschiede auch highlighten könntest ;)

Ja, Ich meinte Boyer-Moore ;) Wusste nur nichtmehr, wie's heißt und dachte damit muss er sich ja nicht unbedingt beschäftigen -> ist doch afaik in Pos() drin?

Naja, egal. Wenn irgendwo Speicherüberschreitungen sind, hat das erstmal Vorrang vor Optimierungen.

mfG,

_________________
Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 05.10.08 13:06 
Nein, Pos arbeitet sequentiell, deshalb hatte ich BM mal selbst als Pos-Ersatz umgesetzt, besonders viel schneller war das meistens aber auch nicht, es lohnt sich eben nicht immer.
Tobi482 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 135



BeitragVerfasst: So 05.10.08 13:15 
Funktioniert
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
     //Jedes Zeichen druchgehen
     j := 0;
     for i := 0 to Size-255-1 do
     begin
          pStrData := pStrData + 'a';

          if isSequenceOffset(Cardinal(pData)+i) then
          begin
               j := j + 1;
               Addlog('Sequenz gefunden bei ' + IntToHex(i, 8));
          end;
     end;
     Addlog(IntToStr(j) + ' Sequenzen gefunden');


Funktioniert nicht
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
     //Jedes Zeichen druchgehen
     j := 0;
     for i := 0 to Size-255-1 do
     begin
          //pStrData := pStrData + 'a';

          if isSequenceOffset(Cardinal(pData)+i) then
          begin
               j := j + 1;
               Addlog('Sequenz gefunden bei ' + IntToHex(i, 8));
          end;
     end;
     Addlog(IntToStr(j) + ' Sequenzen gefunden');
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 05.10.08 13:18 
Hast du es mal getestet, wenn nur dieser Code in einem neuen Projekt steckt? Kannst du ein Beispielprojekt anhängen? Dann würde ich mir das mal anschauen, gerade, wenn da irgendwo Speicher überschrieben wird, ist das nicht so einfach so zu sehen, was auch daran liegt, dass isSequenceOffset ja vermutlich eine eigene Funktion ist, oder? (Mal abgesehen davon, dass der Fehler vermutlich gar nicht im geposteten Quelltext steckt.)
Ginger
Hält's aus hier
Beiträge: 2



BeitragVerfasst: So 05.10.08 13:23 
So wie es aussieht funktioniert der Code immer dann wenn in der Schleife ein String angefasst wird.

Wird der Form-Titel geängert, gehts, Ausgabe eines String in eine Datei -> es geht.
Völlig irrelevante Stringoperation + 'a' und es funktioniert.

Ergibt das Sinn?
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 05.10.08 13:26 
Ja, weil es eben vollkommen egal sein kann was du änderst, wenn du einen Fehler mit überschriebene Speicher hast, sondern das Entscheidende ist, dass du etwas änderst.

// EDIT:
Stell dir das so vor: :mrgreen:
Du hast zwei Geschäfte nebeneinander, jetzt breitest du deine Warenauslage (Speicherbereich) bis zu deinem Nachbarn (andere Variable) aus und greifst auf dessen Warenauslage zu (das was in der anderen Variable liegt).
Dabei nimmst du beispielsweise eine Melone aus seiner Auslage heraus und legst Einwickelpapier stattdessen hin (veränderst Inhalt der anderen Variable).

Jetzt steht davor ein Schild in 1 Meter Höhe, dass dies verdeckt, der Fehler bleibt unbemerkt. Nun änderst du das Schild, du veränderst dessen Höhe, so dass die Warenauslage zu sehen ist. Dein Nachbar sieht nun, dass da was fehlt, der Fehler tritt auf. Dabei hatte die Höhe des Schildes nix damit zu tun.
Ginger
Hält's aus hier
Beiträge: 2



BeitragVerfasst: So 05.10.08 13:40 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Ja, weil es eben vollkommen egal sein kann was du änderst, wenn du einen Fehler mit überschriebene Speicher hast, sondern das Entscheidende ist, dass du etwas änderst.
(...)


Das würde aber wiederum bedeuten das ein
ausblenden Delphi-Quelltext
1:
main.Caption := 'a';					

in der Lage ist einen in einem anderen Programmteil (evtl. isSequenceOffset?) veränderten Speicherbereich wiederherzustellen, denn danach funktioniert es ja.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 05.10.08 13:42 
Nein, es tritt nur zufällig der Fehler nicht mehr auf, weil durch die Veränderung andere Speicherbereiche für folgende Speicheroperationen benutzt werden, denn bei einer Stringoperation werden ggf. neue Strings angelegt o.ä., außerdem ist die Anweisung selbst auch im Speicher, etc. ...
Tobi482 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 135



BeitragVerfasst: So 05.10.08 14:02 
Ok Jungs Danke für eure Hilfe,

ich habe den Fehler gefunden, es war tatsächlich das mit den Melonen. Sobald man einen String initialisiert hat, wurden Speicherbereiche die für den String benutzt wurden "gesäubert" mit 0x00 die später einen Fehler vermieden haben. Ich hatte Arrays vor dem benutzten nicht mit Zeromemory gesäubert. Die initialisierung des Stringspeichers dageben hat die bereiche gesäubert und damit funktionierte isSequenzeOffset. :D

DANKE FÜR EURE HILFE

Mit frendlichen Grüßen Tobi