I would like to declare a record in Delphi that contains the same layout as it has in C.
For those interested : This record is part of a union in the Windows OS's LDT_ENTRY record. (I need to use this record in Delphi because I'm working on an Xbox emulator in Delphi - see project Dxbx on sourceforge).
Anyway, the record in question is defined as:
struct { DWORD BaseMid : 8; DWORD Type : 5; DWORD Dpl : 2; DWORD Pres : 1; DWORD LimitHi : 4; DWORD Sys : 1; DWORD Reserved_0 : 1; DWORD Default_Big : 1; DWORD Granularity : 1; DWORD BaseHi : 8; } Bits;
As far as I know, there are no bit-fields possible in Delphi. I did try this:
Bits = record BaseMid: Byte; // 8 bits _Type: 0..31; // 5 bits Dpl: 0..3; // 2 bits Pres: Boolean; // 1 bit LimitHi: 0..15; // 4 bits Sys: Boolean; // 1 bit Reserved_0: Boolean; // 1 bit Default_Big: Boolean; // 1 bit Granularity: Boolean; // 1 bit BaseHi: Byte; // 8 bits end;
But alas: it's size becomes 10 bytes, instead of the expected 4. I would like to know how I should declare the record, so that I get a record with the same layout, the same size, and the same members. Preferrably without loads of getter/setters.
TIA.
Again, storage of bit fields in memory is done with a byte-by-byte, rather than bit-by-bit, transfer.
Bit fields can be used to reduce memory consumption when a program requires a number of integer variables which always will have low values. For example, in many systems storing an integer value requires two bytes (16-bits) of memory; sometimes the values to be stored actually need only one or two bits.
In programming terminology, a bit field is a data structure that allows the programmer to allocate memory to structures and unions in bits in order to utilize computer memory in an efficient manner. Since structures and unions are user-defined data types in C, the user has an idea of how much memory will they occupy.
Bit fields are portable, in the sense that they are a part of the C language as specified in the standard (C11 section 6.7. 2.1). Any compiler that fails to recognise code that uses bitfields is not standard-compliant.
Thanks everyone!
Based on this information, I reduced this to :
RBits = record public BaseMid: BYTE; private Flags: WORD; function GetBits(const aIndex: Integer): Integer; procedure SetBits(const aIndex: Integer; const aValue: Integer); public BaseHi: BYTE; property _Type: Integer index $0005 read GetBits write SetBits; // 5 bits at offset 0 property Dpl: Integer index $0502 read GetBits write SetBits; // 2 bits at offset 5 property Pres: Integer index $0701 read GetBits write SetBits; // 1 bit at offset 7 property LimitHi: Integer index $0804 read GetBits write SetBits; // 4 bits at offset 8 property Sys: Integer index $0C01 read GetBits write SetBits; // 1 bit at offset 12 property Reserved_0: Integer index $0D01 read GetBits write SetBits; // 1 bit at offset 13 property Default_Big: Integer index $0E01 read GetBits write SetBits; // 1 bit at offset 14 property Granularity: Integer index $0F01 read GetBits write SetBits; // 1 bit at offset 15 end;
The index is encoded as follows : (BitOffset shl 8) + NrBits
. Where 1<=NrBits<=32 and 0<=BitOffset<=31
Now, I can get and set these bits as follows :
{$OPTIMIZATION ON} {$OVERFLOWCHECKS OFF} function RBits.GetBits(const aIndex: Integer): Integer; var Offset: Integer; NrBits: Integer; Mask: Integer; begin NrBits := aIndex and $FF; Offset := aIndex shr 8; Mask := ((1 shl NrBits) - 1); Result := (Flags shr Offset) and Mask; end; procedure RBits.SetBits(const aIndex: Integer; const aValue: Integer); var Offset: Integer; NrBits: Integer; Mask: Integer; begin NrBits := aIndex and $FF; Offset := aIndex shr 8; Mask := ((1 shl NrBits) - 1); Assert(aValue <= Mask); Flags := (Flags and (not (Mask shl Offset))) or (aValue shl Offset); end;
Pretty nifty, don't you think?!?!
PS: Rudy Velthuis now included a revised version of this in his excellent "Pitfalls of converting"-article.
Rudy's Delphi Corner is the best resource I know of regarding Delphi and C/C++ interoperability. His Pitfalls of conversion is pretty much a must read when using C/C++ APIs in Delphi. The chapter you'll be most interested in is Records and alignment -> Bitfields, but I urge you to read the entire thing top to bottom, twice. The other articles are definitely worth the time investment, too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With