Bit manipulation/de

From Lazarus wiki
Jump to navigationJump to search

Deutsch (de) English (en) français (fr)


Maskierte Operationen

Dieses Beispiel ist ein einfacher Ansatz zur Bit-Manipulation. Das Beispiel bietet den Vorteil, dass Operationen, mit Bit-Gruppen, auf einmal durchgeführt werden.

procedure ClearBit(var Value: QWord; Index: Byte);
begin
  Value := Value and ((1 shl Index) xor High(QWord)));
end;

procedure SetBit(var Value: QWord; Index: Byte);
begin
  Value := Value or (QWord(State) shl Index);
end;

procedure PutBit(var Value: QWord; Index: Byte; State: Boolean); 
begin
  Value := (Value and ((1 shl Index) xor High(QWord))) or (QWord(State) shl Index);
end;

function GetBit(Value: QWord; Index: Byte): Boolean;
begin
  Result := ((Value shr Index) and 1) = 1;
end;


Bitpacked record

Die Verwendung von bitpacked records, wird durch die lokale Compilerdirektive {$BITPACKING ON} ermöglicht.

Der Free Pascal Compiler bietet die Möglichkeit einzelne Bits im Speicher anzusprechen. Mit dem Beispiel kann sowohl das ganze Byte als auch das einzelne Bit in diesem Byte angeprochen werden.
Dies kann man mit einem Record oder einem Array lösen.

  ...
  
  // Compilerdirektive
  {$BITPACKING ON}
  
  ...
  
type
  TByteBits = bitpacked record
    Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7: Boolean;
  end;

  TByteEx = packed record
    case Integer of
      0: (ByteAccess: Byte);
      1: (BitAccess: TByteBits);
      3: (BitArray: bitpacked array[0..7] of Boolean);
  end;
  
  ...


Beispiel für die Verwendung von TByteBits und TByteEx:

  // Wertzuweisung als Byte
  ByteEx.ByteAccess := 4;

  // Ändert den Wert von Bit7 und damit den Wert
  // der über ByteEx.ByteAccess wieder ausgelesen wird
  // in diesem Beispiel beträgt der Wert in 
  // ByteEx.ByteAccess 132
  ByteEx.BitAccess.Bit7 := True;

  // Über die Array
  ByteEx.BitArray[7] := True;


Set


In Sets kann man die Bits eintragen, die für die Bitmanipulation in frage kommen.

  
  ...
  
  // Compilerdirektiven
  {$packset 1}
  {$packenum 1}
  
  ...
  
  type
    TSetByteBits = set of (Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7);
  
  ...
  
  var
    SetByteBits: TSetByteBits;
    ...
    
  begin
    
    ...
    
    // legt fest, welche Elemente im Set gespeichert werden
    SetByteBits := [Bit0 .. Bit7];
    
    // Startet eine Bitmanipulation, wenn Bit3 im Set gefunden wird
    if Bit3 in SetByteBits then
    begin
      ...
    end;
    
    ...
    
  end;
  
  ...


TBits


Diese Klasse ist Teil der Klasse Unit aus der Free Pascal RTL Bibliothek. Die Klasse bietet einige Methoden zur Bit-Manipulation.

   TBits = class(TObject)
   public
      constructor Create(TheSize : longint = 0); virtual;
      destructor Destroy; override;
      function  GetFSize : longint;
      procedure SetOn(Bit : longint);
      procedure Clear(Bit : longint);
      procedure Clearall;
      procedure AndBits(BitSet : TBits);
      procedure OrBits(BitSet : TBits);
      procedure XorBits(BitSet : TBits);
      procedure NotBits(BitSet : TBits);
      function  Get(Bit : longint) : boolean;
      procedure Grow(NBit : longint);
      function  Equals(Obj : TObject): Boolean; override; overload;
      function  Equals(BitSet : TBits) : Boolean; overload;
      procedure SetIndex(Index : longint);
      function  FindFirstBit(State : boolean) : longint;
      function  FindNextBit : longint;
      function  FindPrevBit : longint;

      // Funktionen und Eigenschaften zu entsprechen TBits class
      function OpenBit: longint;
      property Bits[Bit: longint]: Boolean read get write SetBit; default;
      property Size: longint read FBSize write setSize;
   end;


Beispiel für eine Verwendung:

    ...
    
  var
    Bits: TBits;
    bytI: Byte;
    
  begin
    
    ...
    
    // Erstellt das Objekt
    Bits := TBits.Create;
    
    // Legt die Grösse fest
    Bits.Size := 5;
    
    // legt für einige Bits den Wert fest
    Bits[0] := true;
    Bits[1] := true;
    Bits[4] := true;
    
    // Ausagbe der Werte
    for bytI := 0 to Bits.Size-1 do
      if Bits[bytI] = true
      then ShowMessage(inttostr(bytI) + '  ' + BoolToStr(Bits[bytI]))
      else ShowMessage(inttostr(bytI) + '  ' + BoolToStr(Bits[bytI]));

    // gibt den Speicher des Objektes wieder frei
    Bits.Free;
    
    ...
  
  end;
  
  ...


Record Eigenschaften und Wertindex


Another interesting implementation of bit aligned structure can be used with capabilities of advanced records (FPC 2.6.0+). For all properties you have to use setter and getter which can handle general bit manipulations and set index which is passed to these methods. For more information refer to Indexed properties. Because index is only one, it has to be divided to two parameters to describe location and size on bit value. In case of the following example, the offset can be 0..255 and size of value 0..255 bits. Another problem is that you have to ensure that defined structure components will not overlay.

{$mode delphi}

  TSomeBitStructure = record
  private
    RawData: Word;
    function GetBits(const AIndex: Integer): Integer; inline;
    procedure SetBits(const AIndex: Integer; const AValue: Integer); inline;
  public
    // High byte of index offset, low byte of index is bit count
    property OneBit: Integer index $0001 read GetBits write SetBits;
    property TwoBits: Integer index $0102 read GetBits write SetBits;
    property FourBits: Integer index $0304 read GetBits write SetBits;
    property EightBits: Integer index $0708 read GetBits write SetBits;
  end;

{$OPTIMIZATION ON}
{$OVERFLOWCHECKS OFF}
function TSomeBitStructure.GetBits(const AIndex: Integer): Integer;
var
  Offset: Integer;
  BitCount: Integer;
  Mask: Integer;
begin
  BitCount := AIndex and $FF;
  Offset := AIndex shr 8;
  Mask := ((1 shl BitCount) - 1);
  Result := (RawData shr Offset) and Mask;
end;

procedure TSomeBitStructure.SetBits(const AIndex: Integer; const AValue: Integer);
var
  Offset: Integer;
  BitCount: Integer;
  Mask: Integer;
begin
  BitCount := AIndex and $FF;
  Offset := AIndex shr 8;
  Mask := ((1 shl BitCount) - 1);
  Assert(aValue <= Mask);
  RawData := (RawData and (not (Mask shl Offset))) or (AValue shl Offset);
end;