Autor Beitrag
Christian213
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 66
Erhaltene Danke: 3

Win XP, Win 7 64Bit
Lazarus 1.0.10
BeitragVerfasst: Do 27.06.13 09:10 
Hallo,

ich habe hier eine gefühlte Ewigkeit an einem merkwürdigen Problem im Zusammenhang mit "ReadBinaryData" rumgedoktort.
Laut Funktionsdefinition ist ReadBinaryData(const Name: string; var Buffer; BufSize: Integer): Integer;
So, also im Prinzip auf dem gewohnten Weg ein OpenKey einen Pfad öffnen, dann einfach einen vorher definierten Puffer nebst Puffergröße übergeben und als Returncode bekommen wir die Anzahl der tatsächlich gelesenen Zeichen, richtig?
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
              bytesRead := regist.GetDataSize(Value);
              if bytesRead > 0 then
              begin
                SetLength(Buffer, bytesRead);
                regist.ReadBinaryData(Value, Buffer, bytesRead);

                (...)
 
              end;

Leider gibt es dann einen SIGSEGV in dem Moment, wo ReadBinaryData aufgerufen wird.

Nach langem Probieren habe ich nun folgende Lösung:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
              bytesRead := regist.GetDataSize(Value);
              if bytesRead > 0 then
              begin
                SetLength(Buffer, bytesRead);
                pBuffer := Pointer(Buffer);
                regist.ReadBinaryData(Value, pBuffer^, bytesRead);
                
                (...)

              end;

Die Frage die sich mir stellt ist: Wieso muss ich eine untypisierte Pointer-Variable definieren und diese dann de-referenziert übergeben?
Es funktioniert so zwar, ich wüsste nur gerne warum ich hier solche Verrenkungen machen muss.

Gruß,
Christian


Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am Do 27.06.2013 um 11:33
Gammatester
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 328
Erhaltene Danke: 101



BeitragVerfasst: Do 27.06.13 09:45 
user profile iconChristian213 hat folgendes geschrieben Zum zitierten Posting springen:
Die Frage die sich mir stellt ist: Wieso muss ich eine untypisierte Pointer-Variable definieren und diese dann de-referenziert übergeben?
Mußt Du das wirklich? Das ist mM die gleiche Situation wie zB bei system.move, also sollte doch eigentlich auch regist.ReadBinaryData(Value, Buffer[0], bytesRead); funktionieren.

Für diesen Beitrag haben gedankt: Christian213
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Do 27.06.13 09:47 
Hi!

Mein Vorschlag wäre erstmal:
ausblenden Delphi-Quelltext
1:
2:
                SetLength(Buffer, bytesRead);
                regist.ReadBinaryData(Value, Buffer[0], bytesRead);

Hintergrund: untypisierte Parameter sind sowas ähnliches wie Pointer, die auf der andern Seite direkt dereferenziert werden. Du willst hier also die das erste Element angeben. Bei dynamischen Arrays liegt das aber grade nicht an der Stelle, wo die Variable ist: wie bei Strings ist "Buffer" erstmal nur ein Zeiger (mit angehängter Längenangabe) auf einen Speicherbereich, wo dann die echten Daten sind.

Bei einem Array mit fester Länge würde das übrigens funktionieren, da dort die Variable direkt den Speicherbereich bezeichnet und damit immer mit dem ersten Element identisch ist, ohne die weitere Ebene Verpointerung dazwischen.

Warum funktioniert dein Pointer?
Wie erwähnt ist Buffer ein Zeiger auf einen Speicherbereich. Pointer() (nicht Ptr() oder @) ist nur ein Typecast, du tust also nichts weiter, als dem Zeiger in Buffer folgen. Genau das also was passiert, wenn du auf das erste Element zugreifst.

An der Stelle mag ich FPC auch wieder, Delphi würde den Code vermutlich anstandslos ausführen, aber er würde nicht funktionieren. Durch den SegFault weißt du wenigstens direkt, dass du irgendwo wild im Speicher rumschreibst ;-)


... und da war der user profile iconGammatester schneller :zwinker:

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."

Für diesen Beitrag haben gedankt: Christian213
Christian213 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 66
Erhaltene Danke: 3

Win XP, Win 7 64Bit
Lazarus 1.0.10
BeitragVerfasst: Do 27.06.13 10:24 
Hallo,

Danke für die Antworten.
Ihr habt natürlich Recht: Es geht auch mit Buffer[0].
Der Unterschied in der Adressierung war mir irgendwie gerade entfallen.
So macht das Ganze auch für mich wieder Sinn.

Gruß
Christian
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 28.06.13 21:53 
user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
An der Stelle mag ich FPC auch wieder, Delphi würde den Code vermutlich anstandslos ausführen, aber er würde nicht funktionieren. Durch den SegFault weißt du wenigstens direkt, dass du irgendwo wild im Speicher rumschreibst ;-)
Das hat nichts mit FPC oder Delphi zu tun, die Schutzverletzung kommt von Windows und das auch nur zufällig, weil der Speicher an der Stelle bekannt ist als nicht beschreibbar...
Setze vorher einfach mal den Pointer auf einen Bereich, der nicht ungültig ist und es kommt auch bei FPC keine Fehlermeldung.