Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Array of AnsiChar vs. ShortString


Gausi - Di 14.08.12 19:46
Titel: Array of AnsiChar vs. ShortString
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:


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:


Martok - 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.


Gausi - 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


Delphi-Laie - 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 - 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:

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.


Delphi-Laie - 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 - 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.