[DUG] [computing] Sizeof record gives error

David Moorhouse delphi at moorhouse.net.nz
Mon Aug 29 17:40:36 NZST 2011


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 :)

However, the compiler gets the size right using New rather than GetMem 
:) So thanks for the tip.

Cheers

D




On 29/08/11 16:23, Jolyon Smith wrote:
> Is it a compiler *error* or just a compiler _behaviour_ ?
>
> 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.
>
> 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).
>
> NOTE:   sizeof(String) also yields "4" even though we all know that a 
> String variable requires many more bytes than that.
>
>
> 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...:
>
> Instead of >>   LogData := GetMem( ... );
>
> Use >>   New( LogData );
>
> And see if you get better results.  :)
>
> (Also, don't forget to use "Dispose()" to deallocate the memory 
> obtained with "New()", rather than FreeMem())
>
>
> On 28 August 2011 21:33, David Moorhouse (DUG) 
> <delphi at moorhouse.net.nz <mailto:delphi at moorhouse.net.nz>> wrote:
>
>     I believe it is a compiler error and will raise a QA ticket
>
>     Thanks for your  help
>
>
>     D
>
>
>     On 26/08/11 08:17, Peter Ingham wrote:
>     > Try filling LogData with binary zeros after the Getmem&  before
>     the assign.
>     >
>     > FillChar (LogData^, sizeof(TLogData), 0);
>     >
>     > I believe the uninitialized memory is messing up the compiler magic
>     > associated with the dynamic array.
>     >
>     >
>     > Any reason the local Tlogdata record is referenced via a pointer?
>     >
>     > I suspect the following will also work:
>     > procedure TUserClass.Log(const LogType: TLogType; const Args:
>     array of
>     > const );
>     >    var
>     >       LogData: TLogData;
>     >     begin
>     >       LogData.LogType := LogType;
>     >       LogData.LogArgs := CreateConstArray(Args);
>     >       //  ... do some other stuff with the LogData item finally
>     calling
>     >     end;
>     >
>     > Cheers
>     >
>     > On 26/08/2011 1:49 a.m., David Moorhouse wrote:
>     >> Hi Peter
>     >>
>     >> Been there done that :)
>     >>
>     >> The function call is fine.  It is the assignment that causes
>     the AV -
>     >> because the "bucket" is too small.
>     >> Assigning it with 16 bytes fixes the problem, regardless of how
>     many
>     >> items the array holds.
>     >>
>     >> I smell compiler magic in the background.
>     >>
>     >> Cheers
>     >
>     >> D
>     >>
>     >> On 25/08/11 17:29, Peter Ingham wrote:
>     >>> Another attempt to reply...
>     >>>
>     >>> First thing to do is determine if the crash occurs in the
>     procedure call,
>     >>> on the subsequent assign, or in between.
>     >>>
>     >>> Give this a try:
>     >>>    procedure TUserClass.Log(const LogType: TLogType; const
>     Args: array of
>     >>>    const );
>     >>>    var
>     >>>      LogData: PLogData;
>     >>>     TempArgs : TConstArray;
>     >>>    begin
>     >>>        // size of record TLogData does not work
>     >>>        GetMem(LogData, sizeof(TLogData));
>     >>>        LogData.LogType := LogType;
>     >>>    // blows up on one of these lines
>     >>>        TempArgs  := CreateConstArray(Args);
>     >>>        LogData.LogArgs := TempArgs;
>     >>>    //  ... do some other stuff with the LogData item finally
>     calling
>     >>> FreeMem
>     >>>    end;
>     >>>
>     >>>
>     >>> Regarding the size of a dynamic array,  like a string
>     variable,  the
>     >>> variable (LogArgs in this case) is the size of a pointer (i.e.
>     4 bytes
>     >>> for Win32).  If the pointer is non-zero, it points to a
>     structure which
>     >>> includes the adjacent array elements preceded by a length.
>     >>>
>     >>> One thing to watch out for is that Getmem does not clear the
>     allocated
>     >>> memory, so LogData after the Getmem call will contain any old
>     rubbish.
>     >>> The reference to LogData.LogArgs in the assignment may be
>     >>> dereferencing a non-zero pointer&   attempting to use whatever it
>     >>> contains.
>     >>>
>     >>> Cheers
>     >>>
>     >>>
>     >>> On 25/08/2011 11:40 a.m., David Moorhouse (DUG) wrote:
>     >>>> I have the following code snippet
>     >>>>
>     >>>> <code>
>     >>>> type
>     >>>>      PConstArray = ^TConstArray;
>     >>>>      TConstArray = array of TVarRec;
>     >>>>
>     >>>> function CreateConstArray(const Elements: array of const):
>     TConstArray;
>     >>>>
>     >>>> type
>     >>>>      TLogType = (ltError, ltWarn, ltInfo);
>     >>>>      PLogData = ^TLogData;
>     >>>>      TLogData = record
>     >>>>        LogType: TLogType;
>     >>>>        LogArgs: TConstArray;
>     >>>>      end;
>     >>>>
>     >>>> ....
>     >>>>
>     >>>> procedure TUserClass.Log(const LogType: TLogType; const Args:
>     array of
>     >>>> const );
>     >>>> var
>     >>>>      LogData: PLogData;
>     >>>> begin
>     >>>>        // size of record TLogData does not work
>     >>>>        GetMem(LogData, sizeof(TLogData));
>     >>>>        LogData.LogType := LogType;
>     >>>> // blows up on next line
>     >>>>        LogData.LogArgs := CreateConstArray(Args);
>     >>>> //  ... do some other stuff with the LogData item finally calling
>     >>>> FreeMem
>     >>>> end;
>     >>>>
>     >>>> function CreateConstArray(const Elements: array of const):
>     TConstArray;
>     >>>> var
>     >>>>      I: Integer;
>     >>>> begin
>     >>>>      SetLength(Result, Length(Elements));
>     >>>>      for I := Low(Elements) to High(Elements) do
>     >>>>        Result[I] :=  // assign a TVarRec here
>     >>>> end;
>     >>>> </code>
>     >>>>
>     >>>> The code that assigns the memory only assigns 8 bytes - and
>     an access
>     >>>> violation ensues.  If I replace the call to "sizeof" with the
>     number 16,
>     >>>> the code works fine.
>     >>>>
>     >>>> My understanding of dynamic arrays was that the compiler
>     created a 4
>     >>>> byte
>     >>>> field before the first element that contained the length of
>     the array.
>     >>>>
>     >>>> So why does the sizeof  function not reflect this ?  And why do I
>     >>>> need 16
>     >>>> bytes not 12  (4 for LogType + 4 for length of array + 4 for
>     array
>     >>>> pointer)?
>     >>>> Also regardless of the number of items in the open array
>     parameter, 16
>     >>>> bytes works, so it does not relate the length of the TConstArray.
>     >>>>
>     >>>> Your thoughts ?
>     >>>>
>     >>>> David
>     >>>>
>     >>>>
>     >>>>
>     >>>> _______________________________________________
>     >>>> NZ Borland Developers Group - Delphi mailing list
>     >>>> Post: delphi at delphi.org.nz <mailto:delphi at delphi.org.nz>
>     >>>> Admin: http://delphi.org.nz/mailman/listinfo/delphi
>     >>>> Unsubscribe: send an email to delphi-request at delphi.org.nz
>     <mailto:delphi-request at delphi.org.nz> with
>     >>>> Subject: unsubscribe
>     >>>>
>     >>
>     >> _______________________________________________
>     >> NZ Borland Developers Group - Delphi mailing list
>     >> Post: delphi at delphi.org.nz <mailto:delphi at delphi.org.nz>
>     >> Admin: http://delphi.org.nz/mailman/listinfo/delphi
>     >> Unsubscribe: send an email to delphi-request at delphi.org.nz
>     <mailto:delphi-request at delphi.org.nz> with Subject: unsubscribe
>     >>
>     > _______________________________________________
>     > NZ Borland Developers Group - Delphi mailing list
>     > Post: delphi at delphi.org.nz <mailto:delphi at delphi.org.nz>
>     > Admin: http://delphi.org.nz/mailman/listinfo/delphi
>     > Unsubscribe: send an email to delphi-request at delphi.org.nz
>     <mailto:delphi-request at delphi.org.nz> with Subject: unsubscribe
>
>
>     _______________________________________________
>     NZ Borland Developers Group - Delphi mailing list
>     Post: delphi at delphi.org.nz <mailto:delphi at delphi.org.nz>
>     Admin: http://delphi.org.nz/mailman/listinfo/delphi
>     Unsubscribe: send an email to delphi-request at delphi.org.nz
>     <mailto:delphi-request at delphi.org.nz> with Subject: unsubscribe
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://listserver.123.net.nz/pipermail/delphi/attachments/20110829/f36a72e6/attachment-0001.html 


More information about the Delphi mailing list