Autor Beitrag
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8553
Erhaltene Danke: 479

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Di 14.08.12 19:46 
Ich hab da mal ne Frage, warum etwas nicht klappt, bzw. was da intern passiert. IDE ist Delphi 2009.

Ich habe einen Filestream, aus dem ich an einer bestimmten Stelle einen kurzen AnsiString (= 4 Zeichen lang) auslesen möchte.

Das habe ich zuerst so probiert:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
type TAtomName = String[4];

var AtomName: TAtomName;
    fs: TFileStream;
//...
fs.Read(AtomName[1], 4);


Klappt aber nicht, d.h. AtomName ist leer. Mit fs.Read(AtomName[0], 4); wird der erwartete String ausgegeben, mit Aunahme des ersten Zeichens. Also statt "moov" nur ein "oov". Was ja irgendwie teilweise logisch ist... :gruebel:

Mit type TAtomName = AnsiString; und zusätzlichem SetLength(AtomName, 4); klappt es korrekt.

Ebenso klappt es mit type TAtomName = Array[1..4of AnsiChar; - Die Lösung passt mir auch ganz gut, da ich mich nicht um SetLength etc. kümmern muss, und das Array of Char trotzdem mit einem String vergleichen kann.

Aber warum klappt es nicht mit dem ShortString? :gruebel:

_________________
We are, we were and will not be.
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: Di 14.08.12 20:55 
user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
Aber warum klappt es nicht mit dem ShortString? :gruebel:
Weil das SetLength fehlt ;)

ShortStrings haben keine fixe, sondern eine Maximallänge. Index [0] ist das Längenbyte... schreib da eine 4 rein (was SetLength auf ShortStrings tut), dann passts.

_________________
"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: Gausi
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8553
Erhaltene Danke: 479

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Di 14.08.12 21:34 
Ah, das erklärt das Verhalten :think:.

Initialisiert wird der String[4] mit 5 0-Bytes (4 Chars + Längenbyte). Wenn ich in die Chars was reinlese, bleibt das Längenbyte unberührt, und die Compilermagic bei Stringtypen-Konvertierungen guckt zuerst darauf, und nicht auf den eigentlichen Inhalt (wovon ich ausgegangen bin).

Danke, Frage geklärt. Dann bleib ich bei dem Array of Char, um mir das Setlength zu sparen. :D

_________________
We are, we were and will not be.
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: Di 14.08.12 23:28 
Begreifen tue ich das nicht.

Mit string[4] wird doch die (maximale) Stringlänge definiert?!

Typ(definition)en der Art "String[x]" kannte doch auch schon Turbo-Pascal, dem Setlength noch völlig fremd war.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19339
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 15.08.12 06:03 
user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Mit string[4] wird doch die (maximale) Stringlänge definiert?!
Eben, die maximale, aber nicht die aktuelle. Das kannst du auch ganz leicht ausprobieren:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
type
  TAtomName = String[4];
var
  AtomName: TAtomName;
begin
  ShowMessage(IntToStr(PByte(@AtomName[0])^));
  AtomName := 'mo';
  ShowMessage(IntToStr(PByte(@AtomName[0])^));
  AtomName := 'moov';
  ShowMessage(IntToStr(PByte(@AtomName[0])^));
end;
Zuerst wird 0, dann 2, dann 4 ausgegeben.

Delphi muss beim Auslesen des Strings ja wissen wie viele Zeichen da überhaupt gerade drin sind. Deshalb reicht die maximale Stringlänge als Information nicht aus.

Für diesen Beitrag haben gedankt: Delphi-Laie
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: Mi 15.08.12 14:14 
Danke, aber ganz klar ist es immer noch nicht.

Das erste Byte ist das Längenbyte, und zwar für die aktuelle Länge (nicht die maximale) - soweit so gut. M.E. muß man da aber nicht unbedingt mit Setlength "herummachen", weil die Länge ja automatisch dort erfaßt und ggf. angepaßt, aktualisiert wird. Setlength benutzte ich bisher immer nur für (logischerweise dynamische) Arrays. In Turbo-Pascal waren auch schon Strings verminderter Länger verfüg-/deklarierbar, und damals gab es schließlich auch noch kein Setlength.

Wo wird nun aber die zusätzliche Information der maximalen Stringlänge gespeichert? Deklariert wird sie ja zur Entwurfszeit, aber wie gelangt sie in das Compilat, wie werden Überläufe bei Überschreiten der deklarierten Arraylänge erkannt und abgefangen (vermutlich Exceptions)?
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19339
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 15.08.12 14:46 
user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
M.E. muß man da aber nicht unbedingt mit Setlength "herummachen", weil die Länge ja automatisch dort erfaßt und ggf. angepaßt, aktualisiert wird.
Ja, wenn du normal hineinschreibst, aber nicht wenn du - und darum geht es in dem Thread ja - nur die Bytes rein wirfst.

user profile iconDelphi-Laie hat folgendes geschrieben Zum zitierten Posting springen:
Wo wird nun aber die zusätzliche Information der maximalen Stringlänge gespeichert? Deklariert wird sie ja zur Entwurfszeit, aber wie gelangt sie in das Compilat, wie werden Überläufe bei Überschreiten der deklarierten Arraylänge erkannt und abgefangen (vermutlich Exceptions)?
Gespeichert? Direkt gar nicht, abgesehen von der RTTI. Nur der Compiler braucht die Information. Der generiert den Code dann dementsprechend, so dass längere Strings abgeschnitten werden usw.

Für diesen Beitrag haben gedankt: Delphi-Laie