Ross Levis wrote:
>> Nope. Delphi's AnsiString value actually points to the char field of
>> the struct, not the length field.
>
> I didn't think this was correct because when reading or writing a string
> to a file using blockread or blockwrite, I need to use MyString[1] as
> the reference.
>
> eg. BlockWrite(File1, MyString[1], Length(MyString));
>
> If I specify just MyString, it accesses memory that does not contain the
> string, most likely the length integer which is MyString[0].
>
> Perhaps you can explain to me a bit more on how this works.
Here's the layout of an AnsiString:
Reference count (4 bytes)
Length (4 bytes)
First character (1 byte)
Second character (1 byte)
Third character (1 byte)
...
Nth character (1 byte)
Null character (1 byte)
There are no pointers within the AnsiString structure itself. For a
string of N characters, that's N+9 bytes. A variable of type AnsiString
is always four bytes. It stores a pointer to the main structure, but not
a pointer to the first byte of that structure. Rather, it points to the
*ninth* byte -- the byte occupied by the first character of string data.
When your program reads the length of a string, it subtracts 4 from the
address stored in the AnsiString variable. That new pointer points to
the length field. Dereferencing that address yields the length value.
One way to implement the Length function would be like this:
function Length(const s: AnsiString): LongInt;
var
L: PLongInt;
begin
L := Pointer(s);
if Assigned(L) then begin
Dec(L);
Result := L^;
end else
Result := 0;
end;
Anyway, back to BlockWrite. BlockWrite accepts an untyped const
parameter. If you just call it like this,
BlockWrite(File1, MyString, Length(MyString));
It will write some number of bytes to the file. The first four of those
bytes will be the four bytes occupied by the MyString variable. In other
words, you'd be storing the address of the first character of the
string. It does not touch any of the string structure I described above.
Untyped parameters do not dereference the things you give to them.
If the length of the string is greater than four, then it's uncertain
just what else you're write into that file. It will be some of the
memory adjacent to the MyString variable on the stack. Perhaps some
variables, perhaps a return address, and whatever else the compiler
decided to store there.
The right way to call BlockWrite (and anything that uses untyped
parameters) if as you showed:
BlockWrite(File1, MyString[1], Length(MyString));
With that call, you give BlockWrite the first character of the string,
and it continues reading the adjacent bytes to get the rest of the
string -- however many bytes are indicated by the call to Length.
Everyone will be better off if they just forget there was ever anything
of use at index 0 of a string. For AnsiString and WideString, reading
that value gives a range-check error. For _all_ strings, the Length
function gives the string's length; you can call it without regard for
what kind of string you're really working with.
--
Rob
_______________________________________________
Delphi mailing list -> [email protected]
http://www.elists.org/mailman/listinfo/delphi