No, it is not. The compiler is perfectly correct.<br><br>A "dynamic array" is a reference type. It is a POINTER to a structure that describes a dynamically sized and reference counted array, just as a "String" is a pointer to a structure that describes (in even more detail) a dynamically sized, reference counted String. In fact, an "array of Char", plus twiddly bits. :)<br>
<br><div>sizeof(TObject) = 4</div><div>sizeof(Pointer) = 4</div><div>sizeof(String) = 4</div><div>sizeof(dynamic array) = 4<br><br>Is correct and true because all four types are _pointers_ and (on Win32) a pointer is 32-bits == 4 bytes.<br>
<br>The size of/amount of memory that each variable of those types points _to_ is different, and includes not only the "user data" (at the positive offsets from the address that the pointer references) but also RTL information at *negative* offsets. But "sizeof" is not concerned with (is in fact entirely ignorant of) this data, only the size of the type used to hold the *reference* to that data.<br>
<br><br></div><div>type</div><div> tfoo = record</div><div> bar: array of integer;</div><div> end;</div><div><br></div><div>var</div><div> f: TFoo; // << has a single field holding a *reference* to an empty array of integer;</div>
<div>begin</div><div> // sizeof(f) == 4 at this point - a pointer</div><div><br></div><div> SetLength(f.bar, 20); // makes "bar" big enough for 20 integers - 80 bytes<br><div><br></div><div> // sizeof(f) is STILL *4* at this point because "bar" is still just a pointer. </div>
<div> // Furthermore, sizeof() is evaluated when you *compiled* the code so it cannot know </div><div> // how much memory bar points to even if it wanted to.</div><div>end;</div><div><br></div><div><br></div><div>It is the *initialization* of the memory *referenced* by your dynamic array variable that is crucial to the correct functioning of the "compiler magic" that supports such types. If you run this code in the debugger and place a breakpoint on the "SetLength", when the code stops on that breakpoint open the CPU view and look back and you will see that the compiler has injected a call to "InitializeRecord"... if you look in System.pas you will see that _InitializeRecord in turn calls _InitializeArray.<br>
<br></div><div>It is this sequence of "Initialize" calls that is missing when you simply allocate a chunk of memory and then set a typed pointer to point at it without first doing all the housekeeping necessary to make that chunk of memory *behave* in the way that your typed pointer is going to expect it to.</div>
<div><br></div><div>By all means do that simple memory allocation, but you are then responsible for doing the housekeeping... calling "Initialize".</div><div><br></div><div>Or use "New" and let the RTL take care of any initialisation that may be required.</div>
<div><br></div><div><br></div><div><br><div class="gmail_quote">On 30 August 2011 09:10, Rohit Gupta <span dir="ltr"><<a href="mailto:rohit@cfl.co.nz">rohit@cfl.co.nz</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div bgcolor="#FFFFFF" text="#000000">
Joylon,<br>
<br>
Good point. But I dont think it applies here. Sizeof returns an
incorrect result... Its a compiler flaw.<br><font color="#888888">
<br>
Rohit</font><div><div></div><div class="h5"><br>
<br>
<br>
<br>
On 29/08/2011 8:10 p.m., Jolyon Smith wrote:
<blockquote type="cite">
<div>
<div>Having just looked up the references for New/GetMem it may
not actually be a question of amount of memory allocated after
all, but rather one of correct initialization of the allocated
memory.</div>
<div><br>
</div>
<div>GetMem() does not initialize the allocated memory, New()
does.</div>
<div><br>
</div>
<div>This is explained in the documentation for the
"Initialize()" procedure (it might have been helpful if the
documentation for GetMem() had mentioned this - or the lack
there-of - too - LOL)</div>
<div><br>
</div>
<div>So you might find that GetMem() would have worked had you
also called Initialise() on the pointer afterward (and
Finalize() before calling FreeMem()). But whatever the
underlying reasons it is obviously simply much easier and
safer (less to remember to have to do, less to get wrong in
doing it :)) to use New/Dispose when working with allocations
of variables/structured(typed) memory and use GetMem/FreeMem
when it is strictly speaking *just* unstructured memory you
need (e.g. i/o buffers etc), rather than space for variables.<br>
<br>
Glad it helped with your problem in any event. :)</div>
<div><br>
</div>
<div><br>
<div class="gmail_quote">On 29 August 2011 17:40, David
Moorhouse <span dir="ltr"><<a href="mailto:delphi@moorhouse.net.nz" target="_blank">delphi@moorhouse.net.nz</a>></span>
wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div bgcolor="#FFFFFF" text="#000000"> I'm aware of the
compiler layout behind the scene - and the fact that
regardless of the length of the dynamic array, my call
to GetMem (or New) does NOT have to allocate memory for
the dynamic array's contents, just it's overhead :)<br>
<br>
However, the compiler gets the size right using New
rather than GetMem :) So thanks for the tip.<br>
<br>
Cheers<br>
<font color="#888888"> <br>
D</font>
<div>
<div><br>
<br>
<br>
<br>
<br>
On 29/08/11 16:23, Jolyon Smith wrote:
<blockquote type="cite">Is it a compiler *error* or
just a compiler _behaviour_ ?<br>
<br>
I haven't looked into it in detail, but dynamic
arrays are notoriously slippery when you are
working with them at a low level and alarm bells
started ringing as soon as I saw they were
involved.
<div> <br>
</div>
<div>In particular, a dynamic array is a reference
type, like a string. So whilst their may be
additional RTTI at a negative offset from the
base address of the array, the "array" itself
may well be a pointer, hence "sizeof()" will
return 4 - the size of a pointer - no matter how
many items may be in the array (as opposed to
Length(), obviously).<br>
<br>
NOTE: sizeof(String) also yields "4" even
though we all know that a String variable
requires many more bytes than that.</div>
<div><br>
</div>
<div><br>
As far as this particular example goes, do you
get any better results using the typed New()
function rather than GetMem() which knows
nothing about the "type" of memory required by
the pointer you are initialising and just
blithely allocates the specified number of
bytes...:</div>
<div><br>
</div>
<div>Instead of >> LogData := GetMem( ...
); </div>
<div><br>
</div>
<div>Use >> New( LogData );<br>
<br>
And see if you get better results. :)<br>
<br>
(Also, don't forget to use "Dispose()" to
deallocate the memory obtained with "New()",
rather than FreeMem())<br>
<br>
</div>
<div><br>
<div class="gmail_quote">On 28 August 2011
21:33, David Moorhouse (DUG) <span dir="ltr"><<a href="mailto:delphi@moorhouse.net.nz" target="_blank">delphi@moorhouse.net.nz</a>></span>
wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> I believe it
is a compiler error and will raise a QA
ticket<br>
<br>
Thanks for your help<br>
<font color="#888888"><br>
<br>
D<br>
</font>
<div>
<div><br>
<br>
On 26/08/11 08:17, Peter Ingham wrote:<br>
> Try filling LogData with binary
zeros after the Getmem& before the
assign.<br>
><br>
> FillChar (LogData^,
sizeof(TLogData), 0);<br>
><br>
> I believe the uninitialized memory
is messing up the compiler magic<br>
> associated with the dynamic array.<br>
><br>
><br>
> Any reason the local Tlogdata
record is referenced via a pointer?<br>
><br>
> I suspect the following will also
work:<br>
> procedure TUserClass.Log(const
LogType: TLogType; const Args: array of<br>
> const );<br>
> var<br>
> LogData: TLogData;<br>
> begin<br>
> LogData.LogType := LogType;<br>
> LogData.LogArgs :=
CreateConstArray(Args);<br>
> // ... do some other stuff
with the LogData item finally calling<br>
> end;<br>
><br>
> Cheers<br>
><br>
> On 26/08/2011 1:49 a.m., David
Moorhouse wrote:<br>
>> Hi Peter<br>
>><br>
>> Been there done that :)<br>
>><br>
>> The function call is fine. It
is the assignment that causes the AV -<br>
>> because the "bucket" is too
small.<br>
>> Assigning it with 16 bytes
fixes the problem, regardless of how
many<br>
>> items the array holds.<br>
>><br>
>> I smell compiler magic in the
background.<br>
>><br>
>> Cheers<br>
><br>
>> D<br>
>><br>
>> On 25/08/11 17:29, Peter Ingham
wrote:<br>
>>> Another attempt to reply...<br>
>>><br>
>>> First thing to do is
determine if the crash occurs in the
procedure call,<br>
>>> on the subsequent assign,
or in between.<br>
>>><br>
>>> Give this a try:<br>
>>> procedure
TUserClass.Log(const LogType: TLogType;
const Args: array of<br>
>>> const );<br>
>>> var<br>
>>> LogData: PLogData;<br>
>>> TempArgs : TConstArray;<br>
>>> begin<br>
>>> // size of record
TLogData does not work<br>
>>> GetMem(LogData,
sizeof(TLogData));<br>
>>> LogData.LogType :=
LogType;<br>
>>> // blows up on one of
these lines<br>
>>> TempArgs :=
CreateConstArray(Args);<br>
>>> LogData.LogArgs :=
TempArgs;<br>
>>> // ... do some other
stuff with the LogData item finally
calling<br>
>>> FreeMem<br>
>>> end;<br>
>>><br>
>>><br>
>>> Regarding the size of a
dynamic array, like a string variable,
the<br>
>>> variable (LogArgs in this
case) is the size of a pointer (i.e. 4
bytes<br>
>>> for Win32). If the pointer
is non-zero, it points to a structure
which<br>
>>> includes the adjacent array
elements preceded by a length.<br>
>>><br>
>>> One thing to watch out for
is that Getmem does not clear the
allocated<br>
>>> memory, so LogData after
the Getmem call will contain any old
rubbish.<br>
>>> The reference to
LogData.LogArgs in the assignment may be<br>
>>> dereferencing a non-zero
pointer& attempting to use
whatever it<br>
>>> contains.<br>
>>><br>
>>> Cheers<br>
>>><br>
>>><br>
>>> On 25/08/2011 11:40 a.m.,
David Moorhouse (DUG) wrote:<br>
>>>> I have the following
code snippet<br>
>>>><br>
>>>> <code><br>
>>>> type<br>
>>>> PConstArray =
^TConstArray;<br>
>>>> TConstArray =
array of TVarRec;<br>
>>>><br>
>>>> function
CreateConstArray(const Elements: array
of const): TConstArray;<br>
>>>><br>
>>>> type<br>
>>>> TLogType =
(ltError, ltWarn, ltInfo);<br>
>>>> PLogData =
^TLogData;<br>
>>>> TLogData = record<br>
>>>> LogType:
TLogType;<br>
>>>> LogArgs:
TConstArray;<br>
>>>> end;<br>
>>>><br>
>>>> ....<br>
>>>><br>
>>>> procedure
TUserClass.Log(const LogType: TLogType;
const Args: array of<br>
>>>> const );<br>
>>>> var<br>
>>>> LogData: PLogData;<br>
>>>> begin<br>
>>>> // size of
record TLogData does not work<br>
>>>> GetMem(LogData,
sizeof(TLogData));<br>
>>>> LogData.LogType
:= LogType;<br>
>>>> // blows up on next
line<br>
>>>> LogData.LogArgs
:= CreateConstArray(Args);<br>
>>>> // ... do some other
stuff with the LogData item finally
calling<br>
>>>> FreeMem<br>
>>>> end;<br>
>>>><br>
>>>> function
CreateConstArray(const Elements: array
of const): TConstArray;<br>
>>>> var<br>
>>>> I: Integer;<br>
>>>> begin<br>
>>>> SetLength(Result,
Length(Elements));<br>
>>>> for I :=
Low(Elements) to High(Elements) do<br>
>>>> Result[I] := //
assign a TVarRec here<br>
>>>> end;<br>
>>>> </code><br>
>>>><br>
>>>> The code that assigns
the memory only assigns 8 bytes - and an
access<br>
>>>> violation ensues. If I
replace the call to "sizeof" with the
number 16,<br>
>>>> the code works fine.<br>
>>>><br>
>>>> My understanding of
dynamic arrays was that the compiler
created a 4<br>
>>>> byte<br>
>>>> field before the first
element that contained the length of the
array.<br>
>>>><br>
>>>> So why does the sizeof
function not reflect this ? And why do
I<br>
>>>> need 16<br>
>>>> bytes not 12 (4 for
LogType + 4 for length of array + 4 for
array<br>
>>>> pointer)?<br>
>>>> Also regardless of the
number of items in the open array
parameter, 16<br>
>>>> bytes works, so it does
not relate the length of the
TConstArray.<br>
>>>><br>
>>>> Your thoughts ?<br>
>>>><br>
>>>> David<br>
>>>><br>
>>>><br>
</div>
</div>
</blockquote>
</div>
</div>
</blockquote>
</div>
</div>
</div>
</blockquote>
</div>
</div>
</div>
</blockquote>
<br>
</div></div></div>
<br>_______________________________________________<br>
NZ Borland Developers Group - Delphi mailing list<br>
Post: <a href="mailto:delphi@listserver.123.net.nz">delphi@listserver.123.net.nz</a><br>
Admin: <a href="http://delphi.org.nz/mailman/listinfo/delphi" target="_blank">http://delphi.org.nz/mailman/listinfo/delphi</a><br>
Unsubscribe: send an email to <a href="mailto:delphi-request@listserver.123.net.nz">delphi-request@listserver.123.net.nz</a> with Subject: unsubscribe<br></blockquote></div><br></div></div>