Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Funktionsweise von SetLength (https://www.delphipraxis.net/162176-funktionsweise-von-setlength.html)

stb2050 10. Aug 2011 20:17

Delphi-Version: 5

Funktionsweise von SetLength
 
Hallo Delphi-Gemeinde,

ich versuche momentan, einen Delphi-Code in PHP umzuschreiben, dabei bin ich auf ein Problem gestoßen. Die Funktion SetLength liefert ein uns unverständliches Ergebnis zurück.

Code:
var
  test: string;

begin
    test := '';
    Writeln(test);
    SetLength(test, 3);
    Writeln (test);
    exit;
end.
Das Ergebnis des SetLenght von '' (also von nichts) ist 2NULC (in der CMD-Ausgabe wird nur 2 angezeigt), das NUL ist das ASCI-Zeichen NUL.

Kann das jemand erklären?

Vielen Dank.

Liebe Grüße,
Steffen

Klaus01 10. Aug 2011 20:29

AW: Funktionsweise von SetLength
 
Guten Abend,

die vergößerst das "Array"/den String
füllst ihn aber nicht mit Daten.
Dann kann da auch irgendetwas drin stehen.

Was bringt denn WriteLn(length(test)) für ein Ergebnis.

Grüße
Klaus

Neutral General 10. Aug 2011 20:30

AW: Funktionsweise von SetLength
 
Naja SetLength reserviert Speicher für den String. In dem Fall für 3 Zeichen (= Bytes, wenn AnsiString). Die 3 Bytes sind nicht initialisiert, weshalb dann im String prinzipiell ALLES stehen kann. Es ist reiner Zufall was danach in test steht.

stb2050 10. Aug 2011 20:43

AW: Funktionsweise von SetLength
 
In der Tat, an einem anderen PC wird etwas anderes, als 2 NUL C zurückgegeben.

Das Ergebnis von WriteLn(length(test)) ist übrigens 0.

Ich versuche mal, den Zusammenhang zu erläutern. Ich versuche, die Delphi-Verschlüssung von http://www.swissdelphicenter.ch/de/showcode.php?id=1243 in PHP zu übersetzen. Das hat an fast allen Stellen schon geklappt, doch an folgender Stelle hänge ich:

Code:
I := Map[S[1]] + (Map[S[2]] shl 6) + (Map[S[3]] shl 12) + (Map[S[4]] shl 18);
writeln(I);
SetLength(Result, 3);
writeln(Result);
Move(I, Result[1], Length(Result));
writeln(Result);
Die Ausgabe ist (beim ersten Durchlauf)
9491535
2NULC


Beim zweiten Durchlauf:
4414743
oNULw
ETB]C

Wie kann man das erklären? An anderen PCs sind Zeilen 1 und 3 der Ausgabe gleich, nur Zeile 2 unterscheidet sich.

Liebe Grüße,
Steffen

Delphi-Laie 10. Aug 2011 21:13

AW: Funktionsweise von SetLength
 
Ich benötigte die Setlength-Prozedur für Strings noch nie. Welchen Sinn soll das haben, an der Stringlänge explizit "herumzumachen", wenn/zumal/weil die Stringlänge doch automatisch bei Stringadditionen angepaßt wird?

In der Delphi(3.0)-Hilfe steht dazu folgends:

"Bei einem langen String weist SetLength den mit S angegebenen String mit der neuen Länge erneut zu. Dabei bleiben die im String gespeicherten Zeichen erhalten, jedoch ist der Inhalt des neu zugewiesenen Speicherbereichs nicht definiert."

Also, die ominösen "2NULC" sind demnach wohl "Speicherleichen" und wurden von einem anderen Programm vorher benutzt oder sind (reiner?!) Zufall.

sirius 10. Aug 2011 21:18

AW: Funktionsweise von SetLength
 
Also, dass Zeilen 1 und 3 jemals gleich sind bezweifle ich sehr stark.

Der Rest wurde schon erklärt. Nach setlength die Stringvariable auszugeben - die vorher leer war - ist ziemlich sinnlos. Schlage ein Buch deiner Wahl auf irgendeiner Seite auf und tippe irgendwo in den Text und schau dir die drei Buchstaben links neben deinem Finger an. Die haben dann etwa genau denselben Informationsgehalt wie deine zweite Zeile.


Also:
Delphi-Quellcode:
I := Map[S[1]] + (Map[S[2]] shl 6) + (Map[S[3]] shl 12) + (Map[S[4]] shl 18);
Hier werden 4 Zahlenwerte addiert. Map[s[1]] ist erstmal das erste Zeichen in S, damit gfehst du an die entsprechende Stelle im Array Map (bei "A" z.B. an Stelle 65+1) und schaust welche Zahl dass ist. bei den anderen Summanden ist das etwas ähnlich, nur dass da die Bits noch etwas nach links verschoben werden (du kannst auch mit 2^n multiplizieren; wobei n hier 6, 12 oder 18 ist)

Jetzt hast du im Speicher eine Zahl stehen, genauer ein Integer bestehend aus eigentlich 4 Bytes, also 32bit. Aber wenn du die obige Rechnung genauer ansiehst, siehst du, dass du nur 3 Bytes besetzt hast, weil deine Zahl nicht größer werden kann. Und diese ausgerechneten 3 Bytes siehst du jetzt einfach als 3 Zeichen an.
Das wars.

rollstuhlfahrer 10. Aug 2011 21:25

AW: Funktionsweise von SetLength
 
Ich möchte an dieser Stelle mal sehr vom Thema abweichen:

Von der Sicherheit her, würde ich empfehlen, was vorhandenes zu nehmen (ala AES, Blowfish, Twofish, ...). Für diese Algorithmen gibt es in fast allen Sprachen (Delphi, C, PHP, auch JS) entsprechende Implementierungen, die zueinander kompatibel sind.

Noch was zu PHP: Arrays haben dort keine feste Länge, weshalb es auch keine Funktion wie SetLength() gibt.

Bernhard

stb2050 10. Aug 2011 21:57

AW: Funktionsweise von SetLength
 
@rollstuhlfahrer: Grundsätzlich hast Du Recht - leider ist die Delphi-Verschlüsselung in dem Programm, dessen Daten ich mit PHP entschlüsseln musst, fest enthalten und ich kann nicht davon abweichen.

@sirius: Soweit habe ich das verstanden, ich glaube das mit den Zahlen ist auch nicht das Problem.

Ich vermute, dass mein Unverständnis an der Delphi-Funktion move begründet ist.

Code:
var
  dest : AnsiString;
  source: LongInt;

begin

 source := 9491535;
 dest  :='';

 SetLength(dest, 3);
 Move(source, dest[1], 3);

 Writeln(source);
 Writeln(dest);

end.
Kann mir jemand erklären, warum dest als Ergebnis (drittes Zeichen: CR) ist. Eigentlich sollten ja nur die ersten 3 Zeichen von source in dest kopiert werden. Findet hier irgendwo eine Umkonvertierung statt?

Liebe Grüße,
Steffen

sirius 10. Aug 2011 22:15

AW: Funktionsweise von SetLength
 
Dein Zahl "9491535" schreiben wir mal kurz um in Hex:
00 90 D4 4F
oder als Little Endian
4F D4 90 00

Das da oben steht also im Speicher. mit mov werden die ersten 3 Bytes (also: 4F D4 90) in den String kopiert. Wenn du das jetzt ausgibst, werden die Bytes als ZEichen interpretiert, und jetzt schau mal in eine handelsübliche ASCII/ANSI-Tabelle mit Cp1252.
4F = O
D4 = Ô
90 = É

himitsu 10. Aug 2011 23:36

AW: Funktionsweise von SetLength
 
Tja, in PHP werden Strings eben initialisiert.
Das geschieht in Delphi nicht, aus performancegründen, denn wenn man SetLength verwendet, sollte man danach auch die reservierten Dinge initialisieren, bzw. gleich mit den gewünschten Werten füllen und bei Letzerem wäre eine vorherige automatische Initialisierung nur unnötiger Overhead.

Und wenn jemand es eben nichts befüllt/initialisiert, dann soll man sich auch nicht wundern, wenn etwas unerwartetes darin erscheint.
Genauso wie bei nichtinitialisierten lokalen Variablen. :stupid:


Wenn man das SetLenght hoch genug wählt, dann kann ich euch garantieren, was sich in dem String befinden wird.

Bei kurzen Strings und wird ein Speicherblock vom Delphi-Memory-Manager verwendet und jenachdem ob und für was dieser Speicherblock vorher verwendet wurde, befindet sich doch auch schon "irgendwas" drin.

Wird der String aber größer, als der größte verwaltete Block des MM, wird direkt bei Windows ein Speicherbereich extra für diesen String bestellt und da Windows sowas immer mit 0 initialisiert, wird der String auch auch nur vielen #0 bestehen. :angle2:


PS: Delphi-Referenz durchsuchenDupeString und Delphi-Referenz durchsuchenStringOfChar


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:53 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz