How to simulate bit-fields in Delphi records?

前端 未结 4 2064
终归单人心
终归单人心 2020-12-04 18:32

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 L

4条回答
  •  臣服心动
    2020-12-04 18:49

    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.

提交回复
热议问题