我想在Delphi中声明一个包含与C中相同布局的记录.
对于那些感兴趣的人:此记录是Windows操作系统的LDT_ENTRY记录中的联合的一部分.(我需要在Delphi中使用此记录,因为我正在使用Delphi中的Xbox模拟器 - 请参阅sourceforge上的项目Dxbx).
无论如何,有问题的记录定义为:
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;
据我所知,Delphi中没有可用的位域.我试过这个:
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;
但是唉:它的大小变成了10个字节,而不是预期的4.我想知道如何声明记录,这样我就可以得到一个具有相同布局,相同大小和相同成员的记录.优选没有吸气剂/固定剂的负荷.
TIA.
感谢大家!
根据这些信息,我将其减少为:
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;
索引编码如下:(BitOffset shl 8) + NrBits
.其中1 <= NrBits <= 32且0 <= BitOffset <= 31
现在,我可以按如下方式设置和设置这些位:
{$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;
很漂亮,你不觉得吗?!?!
PS:Rudy Velthuis现在包括了他在出色的"转换陷阱"中的修订版本.
Rudy的Delphi Corner是我所知道的有关Delphi和C/C++互操作性的最佳资源.在Delphi中使用C/C++ API时,他的转换陷阱几乎是必读的.你最感兴趣的章节是记录和对齐 - > Bitfields,但我恳请你从上到下阅读整个内容,两次.其他文章也绝对值得花时间投资.
好吧,我的位操作有点生疏,所以我可以颠倒字节.但是下面的代码给出了一般的想法:
type TBits = record private FBaseMid : Byte; FTypeDplPres : Byte; FLimitHiSysEa: Byte; FBaseHi : Byte; function GetType: Byte; procedure SetType(const AType: Byte); function GetDpl: Byte; procedure SetDbl(const ADpl: Byte); function GetBit1(const AIndex: Integer): Boolean; procedure SetBit1(const AIndex: Integer; const AValue: Boolean); function GetLimitHi: Byte; procedure SetLimitHi(const AValue: Byte); function GetBit2(const AIndex: Integer): Boolean; procedure SetBit2(const AIndex: Integer; const AValue: Boolean); public property BaseMid: Byte read FBaseMid write FBaseMid; property &Type: Byte read GetType write SetType; // 0..31 property Dpl: Byte read GetDpl write SetDbl; // 0..3 property Pres: Boolean index 128 read GetBit1 write SetBit1; property LimitHi: Byte read GetLimitHi write SetLimitHi; // 0..15 property Sys: Boolean index 16 read GetBit2 write SetBit2; property Reserved0: Boolean index 32 read GetBit2 write SetBit2; property DefaultBig: Boolean index 64 read GetBit2 write SetBit2; property Granularity: Boolean index 128 read GetBit2 write SetBit2; property BaseHi: Byte read FBaseHi write FBaseHi; end; function TBits.GetType: Byte; begin Result := (FTypeDplPres shr 3) and $1F; end; procedure TBits.SetType(const AType: Byte); begin FTypeDplPres := (FTypeDplPres and $07) + ((AType and $1F) shr 3); end; function TBits.GetDpl: Byte; begin Result := (FTypeDplPres and $06) shr 1; end; procedure TBits.SetDbl(const ADpl: Byte); begin FTypeDblPres := (FTypeDblPres and $F9) + ((ADpl and $3) shl 1); end; function TBits.GetBit1(const AIndex: Integer): Boolean; begin Result := FTypeDplPres and AIndex = AIndex; end; procedure TBits.SetBit1(const AIndex: Integer; const AValue: Boolean); begin if AValue then FTypeDblPres := FTypeDblPres or AIndex else FTypeDblPres := FTypeDblPres and not AIndex; end; function TBits.GetLimitHi: Byte; begin Result := (FLimitHiSysEa shr 4) and $0F; end; procedure TBits.SetLimitHi(const AValue: Byte); begin FLimitHiSysEa := (FLimitHiSysEa and $0F) + ((AValue and $0F) shr 4); end; function TBits.GetBit2(const AIndex: Integer): Boolean; begin Result := FLimitHiSysEa and AIndex = AIndex; end; procedure TBits.SetBit2(const AIndex: Integer; const AValue: Boolean); begin if AValue then FLimitHiSysEa := FLimitHiSysEa or AIndex else FLimitHiSysEa := FLimitHiSysEa and not AIndex; end;