<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
You're both right. A call to GetMem followed by FillChar with #0
sorts the problem :(<br>
<br>
However I will stick with New as it is a cleaner solution than all
others mentioned :)<br>
<br>
D<br>
<br>
On 30/08/11 12:51, David Brennan wrote:
<blockquote cite="mid:009201cc66ae$f6a59090$e3f0b1b0$@co.nz"
type="cite">
<meta http-equiv="Content-Type" content="text/html;
charset=ISO-8859-1">
<meta name="Generator" content="Microsoft Word 12 (filtered
medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Tahoma;
        panose-1:2 11 6 4 3 5 4 4 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:12.0pt;
        font-family:"Times New Roman","serif";}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
span.EmailStyle17
        {mso-style-type:personal-reply;
        font-family:"Calibri","sans-serif";
        color:#1F497D;}
.MsoChpDefault
        {mso-style-type:export-only;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
<div class="WordSection1">
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D">I
think the sizeof call is irrelevant here (which I believe is
what Jolyon is also saying).<o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D"><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D">The
error occurs on this line:<o:p></o:p></span></p>
<p class="MsoNormal">LogData.LogArgs := CreateConstArray(Args);<span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D"><o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D"><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D">LogArgs
is a dynamic array as is the CreateConstArray result.
Standard Delphi logic is that the memory for the old dynamic
array (ie LogArgs) will be dereferenced and then freed if no
longer used. If LogArgs points to random memory because it
was never initialised then obviously the dereferencing and
subsequent freeing are both extremely likely to blow up.<o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D"><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D">The
compiler usually works pretty hard to make sure dynamic
array variables are initialised to nil but the GetMem call
was bypassing that.<o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D"><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D">Cheers,<o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D">David.
<o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D"><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D"><o:p> </o:p></span></p>
<div style="border:none;border-top:solid #B5C4DF
1.0pt;padding:3.0pt 0cm 0cm 0cm">
<p class="MsoNormal"><b><span
style="font-size:10.0pt;font-family:"Tahoma","sans-serif""
lang="EN-US">From:</span></b><span
style="font-size:10.0pt;font-family:"Tahoma","sans-serif""
lang="EN-US"> <a class="moz-txt-link-abbreviated" href="mailto:delphi-bounces@listserver.123.net.nz">delphi-bounces@listserver.123.net.nz</a>
[<a class="moz-txt-link-freetext" href="mailto:delphi-bounces@listserver.123.net.nz">mailto:delphi-bounces@listserver.123.net.nz</a>] <b>On
Behalf Of </b>Jolyon Smith<br>
<b>Sent:</b> Tuesday, 30 August 2011 12:04 p.m.<br>
<b>To:</b> <a class="moz-txt-link-abbreviated" href="mailto:rohit@cfl.co.nz">rohit@cfl.co.nz</a>; NZ Borland Developers Group -
Delphi List<br>
<b>Subject:</b> Re: [DUG] [computing] Sizeof record gives
error<o:p></o:p></span></p>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal" style="margin-bottom:12.0pt">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. :)<o:p></o:p></p>
<div>
<p class="MsoNormal">sizeof(TObject) = 4<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">sizeof(Pointer) = 4<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">sizeof(String) = 4<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt">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>
<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">type<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> tfoo = record<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> bar: array of integer;<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> end;<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">var<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> f: TFoo; // << has a single
field holding a *reference* to an empty array of integer;<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">begin<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> // sizeof(f) == 4 at this point - a
pointer<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal"> SetLength(f.bar, 20); // makes "bar"
big enough for 20 integers - 80 bytes<o:p></o:p></p>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal"> // sizeof(f) is STILL *4* at this
point because "bar" is still just a pointer. <o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> // Furthermore, sizeof() is
evaluated when you *compiled* the code so it cannot know <o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"> // how much memory bar points to
even if it wanted to.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">end;<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt">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.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">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.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">By all means do that simple memory
allocation, but you are then responsible for doing the
housekeeping... calling "Initialize".<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Or use "New" and let the RTL take care
of any initialisation that may be required.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<p class="MsoNormal">On 30 August 2011 09:10, Rohit Gupta
<<a moz-do-not-send="true"
href="mailto:rohit@cfl.co.nz">rohit@cfl.co.nz</a>>
wrote:<o:p></o:p></p>
<div>
<p class="MsoNormal">Joylon,<br>
<br>
Good point. But I dont think it applies here. Sizeof
returns an incorrect result... Its a compiler flaw.<br>
<span style="color:#888888"><br>
Rohit</span><o:p></o:p></p>
<div>
<div>
<p class="MsoNormal"><br>
<br>
<br>
<br>
On 29/08/2011 8:10 p.m., Jolyon Smith wrote: <o:p></o:p></p>
<div>
<div>
<p class="MsoNormal">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.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">GetMem() does not
initialize the allocated memory, New() does.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">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)<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">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.
:)<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<p class="MsoNormal">On 29 August 2011 17:40,
David Moorhouse <<a
moz-do-not-send="true"
href="mailto:delphi@moorhouse.net.nz"
target="_blank">delphi@moorhouse.net.nz</a>>
wrote:<o:p></o:p></p>
<div>
<p class="MsoNormal">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>
<span style="color:#888888"><br>
D</span> <o:p></o:p></p>
<div>
<div>
<p class="MsoNormal"><br>
<br>
<br>
<br>
<br>
On 29/08/11 16:23, Jolyon Smith wrote:
<o:p></o:p></p>
<p class="MsoNormal">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. <o:p></o:p></p>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">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.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal"><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...:<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal">Instead of
>> LogData := GetMem( ... );
<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal"
style="margin-bottom:12.0pt">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())<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<p class="MsoNormal">On 28 August
2011 21:33, David Moorhouse (DUG)
<<a moz-do-not-send="true"
href="mailto:delphi@moorhouse.net.nz"
target="_blank">delphi@moorhouse.net.nz</a>>
wrote:<o:p></o:p></p>
<p class="MsoNormal">I believe it is
a compiler error and will raise a
QA ticket<br>
<br>
Thanks for your help<br>
<span style="color:#888888"><br>
<br>
D</span><o:p></o:p></p>
<div>
<div>
<p class="MsoNormal"><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>
>>>><o:p></o:p></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
</div>
</div>
<p class="MsoNormal"><br>
_______________________________________________<br>
NZ Borland Developers Group - Delphi mailing list<br>
Post: <a moz-do-not-send="true"
href="mailto:delphi@listserver.123.net.nz">delphi@listserver.123.net.nz</a><br>
Admin: <a moz-do-not-send="true"
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 moz-do-not-send="true"
href="mailto:delphi-request@listserver.123.net.nz">delphi-request@listserver.123.net.nz</a>
with Subject: unsubscribe<o:p></o:p></p>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
</div>
</div>
<br>
<fieldset class="mimeAttachmentHeader"></fieldset>
<br>
<pre wrap="">_______________________________________________
NZ Borland Developers Group - Delphi mailing list
Post: <a class="moz-txt-link-abbreviated" href="mailto:delphi@listserver.123.net.nz">delphi@listserver.123.net.nz</a>
Admin: <a class="moz-txt-link-freetext" href="http://delphi.org.nz/mailman/listinfo/delphi">http://delphi.org.nz/mailman/listinfo/delphi</a>
Unsubscribe: send an email to <a class="moz-txt-link-abbreviated" href="mailto:delphi-request@listserver.123.net.nz">delphi-request@listserver.123.net.nz</a> with Subject: unsubscribe</pre>
</blockquote>
<br>
</body>
</html>