Dial memory layout

How is set organized in memory in Delphi?

I am trying to make a simple type for a set type like

 var MyNumber : Word; ShiftState : TShiftState; begin MyNumber:=42; ShiftState:=TShiftState(MyNumber); end; 

Delphi (2009) will not allow this, and I do not understand why. This would make my life easier in cases where I get a number in which individual bits encode different enum values, and I just could distinguish them. It can be done?

One of the approaches that I was going to do is:

 var ShiftState : TShiftState; MyNumber : Word absolute ShiftState; begin MyNumber:=42; end; 

But before that, I thought I would ask for a memory layout. It is more a feeling than knowing what I have about it right now.

+7
source share
4 answers

A Delphi set is a bit field whose bit corresponds to the associated values ​​of the elements in your set. For a set of normal numbered types, the bit arrangement is straightforward:

  • bit 0 corresponds to a given element with ordinal value 0
  • bit 1 corresponds to a given element with ordinal value 1
  • etc.

Everything becomes a little interesting when you are dealing with an non-contiguous set or with a set that does not start from scratch. You can do this using the Delphi subband type (example: set of 3..7 ) or using the enumerated types that determine the actual ordinal value for the elements:

 type enum=(seven=7, eight=8, eleven=11); EnumSet = set of enum; 

In such cases, Delphi will allocate the minimum required number of bytes, which will include all the necessary bits, but will not β€œshift” the bit values ​​in order to use less space. In the EnumSet example EnumSet Delphi will use two bytes:

  • The first byte will have the 7th bit associated with seven
  • The second byte will have bit 0 associated with eight
  • The second byte will have bit 3 associated with eleven

You can see some tests that I did here: Delphi 2009 - error? Adding allegedly invalid values ​​to the set

Tests were performed using Delphi 2010, did not repeat them for Delphi XE.

+6
source

You must select the correct ordinal type. For me (D2007) your code is compiled using MyNumber: Byte :

 procedure Test; var MyNumber: Byte; ShiftState: TShiftState; begin MyNumber := 42; ShiftState := TShiftState(MyNumber); end; 

I used this technique in some situations and did not encounter any problems.


UPDATE

The TShiftState type TShiftState been expanded since Delphi 2010 includes two new states, ssTouch and ssPen , based on the corresponding document page ( current document page ). The Delphi 2009 doc still has TShiftState defined as a set of 7 states.

So, your attempt to convert Word to TShiftState will work in Delphi 2010+, but Byte is the right size for Delphi 2009.

+1
source

Unfortunately, I just came across the following question: Delphi 2009 - a mistake? Adding allegedly invalid values ​​to the set

Cosmin's accepted answer contains a very detailed description of what happens with sets in Delphi. And why I better not use my approach with absolute . Apparently, the given variable can take from 1 to 32 bytes of memory depending on the values ​​of the enumeration.

+1
source

I use this:

For <= 8 elements, PByte (@MyNumber) ^, for <= 16 elements, PWord (@MyNumber) ^, etc.

If the enumeration takes up more space (via the min enum size compiler parameter), this will still work.

0
source

All Articles