![]() |
Length zerstört AnsiString
Folgende Klasse ist definiert:
Delphi-Quellcode:
Der Konstruktor sieht wie folgt aus:
type
TFlexTransportSDS = class(TObject) strict private FTargetSSI: integer; FMessage: AnsiString; //Nix Unicode FHandle: integer; FIsStatus: Boolean; FStatus: Word; protected public //Die anderen Konstruktoren habe ich hier auskommentiert, sie spielen keine Rolle constructor Create(ATargetSSI: integer; const AMessage: AnsiString; AHandle: integer); //overload; //constructor Create(ATargetSSI: integer; AStatusValue: integer); overload; //constructor Create; overload; property TargetSSI: integer read FTargetSSI write FTargetSSI; property TheMessage: AnsiString read FMessage write FMessage; property SDSHandle: integer read FHandle write FHandle; property IsStatus: boolean read FIsStatus write FIsStatus; property StatusValue: Word read FStatus write FStatus; end;
Delphi-Quellcode:
Nun erzeugen wir eine Instanz dieses neuen Objekts:
constructor TFlexTransportSDS.Create(ATargetSSI: integer; const AMessage: AnsiString; AHandle: integer);
var i: integer; begin FTargetSSI:=ATargetSSI; //Originalcode //FMessage:=AMessage; //funktioniert ebenfalls nicht for i := 1 to Length(AMessage) do FMessage:=FMessage+AMessage[i]; FHandle:=AHandle; end;
Delphi-Quellcode:
Debuggen wir nun durch den Konstruktor hindurch, wird AMessage zerfetzt, es bleibt "#3?????" und eine Menge Nullbytes davon übrig.
var
TF: TFLexTransportSDS; s: AnsiString; begin s:=#3#0'$PSCOCM,21'; TF:=TFlexTransportSDS.Create(104, s, 114); end; Ich hab das ganze dann mit dem Disassember verfolgt und sehe, das Length nur noch mit Unicode-Strings arbeiten kann, ergo erzeugt der Compiler einen Aufruf nach @InternalLStrToUStr, um aus AMessage erstmal Unicode zu machen und dann die Länge zu ermitteln. Offensichtlich ist @InternalLStrToUStr mit einem Problem behaftet: Das erste Zeichen (#3) wird noch erkannt, die folgende #0 aber nicht mehr und die Routine flippt aus ;) Mein Originalstring (AMessage !!) ist anschließend zerstört. Kann das wer nachvollziehen ? Gibt es eine Möglichkeit, Length zu umgehen (StrLen geht wegen des Nullbytes NICHT !) ? Wenn dies ein tatsächlicher Fehler in Delphi ist, verschrotte ich D2009 - wer weiß, was noch für Granaten da schlummern. Compiler ist Delphi 2009 Professional, Update 3 plus Update 4 (Database Pack Update) plus Help Update 3 sind installiert. |
Re: Length zerstört AnsiString
Das "Zerstören" kann ich unter Delphi 2007 wohl nicht nachvollziehen, aber auch ein AnsiString hört beim #0 auf. Wäre Shortstring eine Option?
|
Re: Length zerstört AnsiString
Verwendung von #0 als Teil eines Strings ist eine ganz schlechte Idee. Unter C/C++ würdest du damit keine 3 Quellcodezeilen weit kommen. Falls es sich um ein Transportprotokoll handelt würde ich hier eher mit Streams arbeiten. Du kannst von Glück reden das dein Code bei alten Delphi-Versionen halbwegs funktioniert hat.
|
Re: Length zerstört AnsiString
Ich hatte mal ein ähnliches Problem mit Sonderzeichen, war ziemlich schwer aufzuspüren, weil die Fehler ganz woanders (und nicht immer an der gleichen Stelle) auftraten. Hach, das war eine herrliche Debugging-Session... :love:
Probier mal statt #0 chr(0) zu schreiben (gilt für die anderen Sonderzeichen auch). |
Re: Length zerstört AnsiString
Mal so aus der Hüfte gedacht:
wie wäre es mit einem array of char? das ist kompatibel zu "string" aber die interpretation des Inhalts (#0) fällt weg? Gruß K-H |
Re: Length zerstört AnsiString
Der obere Code sollte funktionieren, da hier zufällig keine "Funktionen" verwendet werden, welche die #0 nicht mögen.
String-Konstante mit #0 ist möglich Concat (String := String + String) ist möglich 'ne einfache Zuweisung (String := String) ist möglich und Übergabe als Parameter geht auch Der Delphi-String benutzt ein LängenenByte (Integer) und ließt nicht die länge anhand einer abschließenden #0 aus ... es gibt aber leider viele Funktionen, welche nach dem C-Standard als PChar arbeiten und auch die oft genutzen WinAPIs arbeiten so C-mäßig. Also wenn man weiß, was man tut, kann man in einem String alle möglichen Steuerzeichen (auch #0) verwenden. (mach ich sehr gern, da ich so das automatische Aufräumen mit ausnutzen kann :angel2: ) Das Problem ist hier vermutlich DELPHI und seine kranke Unicode-Unterstützung und wegen der #0 an 2. Stelle denkt es wäre ein UnicodeString. Schalte das String-Checking ab und gut ist, außerdem wird dadurch das Programm etwas schneller/schlanker. ![]() ![]()
Delphi-Quellcode:
das interessiert Delphi2009/2010 nicht, prüft es ständig nach und ändert es dann einfach
FMessage: AnsiString; //Nix Unicode
|
Re: Length zerstört AnsiString
Zitat:
Um das Phänomen zu umgehen, kannst du einen ShortString verwenden, der benutzt tatsächlich noch das erste Byte als Längenangabe. |
Re: Length zerstört AnsiString
nicht ganz ... der AnsiString und UnicodeString (seit D2009) haben intern 2 Zusätzliche Integer
- Längenangabe - Referenzzählung und, damit man es schön einfach als PChar verwenden kann, eine #0 hintendran, aber von der Stringverwaltung wird nur die Längenangabe verwendet. Allerdings gibt es halt Delphifunktionen, welche c-typisch nur auf #0 reagieren, oder wie z.B. StringReplace, welche zwar selber die Längenangabe auswertet, aber durch Verwendung von ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:06 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz