![]() |
Re: Frage zum Aufbau eines Strings
ohne zu wissen ob das was mirage228 geschrieben hat richtig ist: Klar ist -4 außerhalb des zulässigen. 0 ist auch außerhalb des zulässigen, trotzdem kann man drauf zugreifen (es steht eben nur nicht der String drin). Wenn das von mirage228 stimmt, dann wird einfach genügend speicher reserviert für den String und der Index[1] greift prinzipiell eben erst auf die Xte-Stelle des reservierten Speichers zu und nicht wirklich auf die 1te oder 0te
@Muetze: ist klar das es nur bei den AnsiStrings so ist, ansonsten ist ja wie beim PChar alles an einer Stelle und nicht überall im speicher verteilt mit extra speicherverwaltung (die ist eben wegen den referenzzeugs nur bei den Ansistrings dabei) |
Re: Frage zum Aufbau eines Strings
Ich würd' mir gern mal die Length-Funktion anschauen, um näheres zu erfahren, aber ich finde sie nicht in der System.pas :pale:
|
Re: Frage zum Aufbau eines Strings
Wurde ja alles schon erwähnt, deswegen nur noch mal kurz zusammenfassend.
Der String ist ein Pointer auf einen Speicherbereich. Selbst also nichts anderes als ein Pointer. Dieser Pointer zeigt auf das erste Zeichen des Strings, welches mit StringVar[1] anzusteuern geht. Vor diesem Zeichen gibt es acht weitere Bytes, deren Struktur wie folgend ist (Copyright Borland, System.pas):
Delphi-Quellcode:
Das heisst, die Bytes -8 bis -5 sind der Referenzzähler (wie oft wird dieser String genutzt) und die Bytes -4 bis -1 sind die Länge des Strings.
type
PStrRec = ^StrRec; StrRec = packed record refCnt: Longint; length: Longint; end; Zu Pascalzeiten war es anders, die Strings dort waren so aufgebaut, wie es heute die ShortStrings sind. Diese hatten eine maximale Länge von 255 Zeichen. Das 0. Byte (also StringVar[0]) speicherte die Länge des Strings (0-255) und die folgenden Bytes den Inhalt. Die Strings in den heute gängigen Pascal-Versionen können bis zu 2 GB (nicht 4 GB!) groß werden. Da dieser Wert zum Speichern eindeutig mehr als 1 Byte benötigt, kann dieser Wert (StringVar[0]) für normale Strings auch nicht mehr angesteuert werden (Compiler-Fehlermeldung). ...:cat:... |
Re: Frage zum Aufbau eines Strings
Zitat:
siehe den Hinweis in der System.pas: Zitat:
Edit: Siehe zusätzlich Post von sakura unter mir ;) mfG mirage228 |
Re: Frage zum Aufbau eines Strings
Zitat:
Delphi-Quellcode:
...:cat:...
function _LStrLen(const s: AnsiString): Longint;
{$IFDEF PUREPASCAL} begin Result := 0; if Pointer(s) <> nil then Result := PStrRec(Integer(s) - sizeof(StrRec)).length; end; {$ELSE} asm { -> EAX str } TEST EAX,EAX JE @@done MOV EAX,[EAX-skew].StrRec.length; @@done: end; {$ENDIF} |
Re: Frage zum Aufbau eines Strings
Zitat:
...:cat:... |
Re: Frage zum Aufbau eines Strings
Oh :oops: weiß gar nicht wie ich auf die 4 GB gekommen bin. Hmm, jetzt wo du mich wieder mal dran erinnert hast das ein String ja nur ein Pointer war (sizeof(String) war ja schon immer 4 (war mir entfallen *schäm*)) ist mir das ganze mit dem speicher auch wieder bissl klarer (und vor allem das mit dem -4, -8).
@Sakura: Der Compiler schon, aber wenn man über den umweg der Pointer drauf zugreift kommt keine AV (so hatt ichs eigentli auch versucht) |
Re: Frage zum Aufbau eines Strings
Zitat:
Übergibt man nun einen AnsiString an eine DLL und diese verändert diesen, passiert es, dass der AnsiString an den DLL-Speichermanager zum Freigeben übergeben wird, der mit dem Speicherbereich aber gar nichts anfangen kann, weil der AnsiString ja im EXE-Speichermanager reserviert wurde. In diesem Moment kracht es dann. Bei WideStrings läuft das ganze anders ab. Da WideString hauptsächlich wegen COM eingeführt wurden und auch nicht-Delphi-Anwendungen COM-Server und Clients sein können, war Borland gezwungen, den von Microsoft vorgegebenen WideString-Speichermanager zu benutzen. Deswegen wird bei WideString nicht AllocMem/FreeMem sondern Windows.SysAllocStringLen/SysFreeString aufgerufen. Bei ShortStrings liegt die Sache ganz anders. ShortStrings werden nicht dynamisch reserviert, sondern werden einfach im Datensegment oder auf dem Stack erzeugt. Beim Stack wird ein "SUB ESP,256" für einen lokale Variable "s: ShortString" durchgeführt. Und dieser Speicher muss auch nicht realloziert werden, weil die 255 Zeichen Maximum sind, weswegen der EXE und DLL-Speichermanager sich nicht in die Quere kommen. Also alles was mit AllocMem/GetMem/FreeMem arbeitet (dazu gehören AnsiString, dyn. Array, Klassen, New, Dispose, ...) können nur ohne Probleme an eine DLL übergeben werden, wenn diese nur ohne Reallozierung (ReallocMem) oder Freigeben und neu Reservieren zugreift. Bei AnsiStrings ist es aber sehr wahrscheinlich, dass man den String Realloziert ohne das man das direkt im Code geschrieben hat. Wenn man also die Compiler-Magic für AnsiStrings nicht auswendig kennt, sollte man bei AnsiString sehr vorsichtig sein. Und nun warum das ganze kein Problem bei Packages ist, die ja auch "nur" DLLs sind. Bei Packages hat Borland das DLL-Format dahingehend erweitert, als dass der Compiler alle öffentlichen Funktionen, Methoden und einige spezielle, nur für den Compiler/RTL wichtige Funktionen exportiert. In diesen Compiler-Magic-Funktionen stecken dann so informationen wie welche Unit im Package enthalten sind, ... Diese Informationen erlauben es der RTL nun zu verhindern, dass die BPL einen eigenen Speichermanager bekommt. Somit benutzen die EXE und die BPL ein und denselben Speichermanager, und können somit AllocMem und FreeMem in beiden Modulen ungehindert aufrufen, weil beide auf dieselble Block-List zugreifen. Die BorlandMM.dll macht nun nichts anderes, als dass sie in der EXE und in der DLL mittels der Unit ShareMem, die per SetMemoryManager den Speichermanager der EXE und der DLL auf die BorlandMM.dll setzt, den gleichen Speichermanager für beide Module anbietet und somit AllocMem und FreeMem in beiden Modulen aufgerufen werden können. |
Re: Frage zum Aufbau eines Strings
Zitat:
Code:
Wenn mal also immer von 0 ab zählt und dann mit S[Index+1] zugreift, optimiert der Compiler das zu (ungefähr):
MOV ESI, S
MOV EDX, [Index] MOV AL, [ESI+EDX-1]
Code:
Also wird die -1 entfernt, was ein ganz kleinen, fast unmessbaren Geschwindigkeitszuwachs bringt. Macht aber die Lesbarkeit ein wenig kaputt.
MOV ESI, S
MOV EDX, [Index] MOV AL, [ESI+EDX] Wenn man nun die String S in einen Zeiger konvertiert, entfällt das -1 ganz von alleine, weil es sich ja nicht mehr um einen String handelt. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:24 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-2025 by Thomas Breitkreuz