delphi 在一个字节中最多存储8个布尔值,在一个整数中最多存储32个布尔值

fslejnso  于 2022-11-04  发布在  其他
关注(0)|答案(3)|浏览(176)

我需要存储以下内容:
1.一个Byte中最多8个Boolean

  1. (U)Int32中最多32个Boolean
  2. (U)Int64中最多64个Boolean
    Byte是否比Char更适合8位?
    对于32/64位,我应该使用signed还是unsigned
    是否有一个特定于Delphi的代码示例可以将Byte/Integer转换为Boolean数组,或者将Boolean数组转换为Byte/Integer数组?例如,可以将第N项设置为true/false,例如:
SetItemBoolean(ItemNumber: Integer; Value: Boolean);

我发现了一些东西可以从一个Char转换成一个Boolean数组,我只是想知道如何对Byte/Integer进行转换,这样我就可以支持更多的Boolean值。
https://ibeblog.com/2010/08/20/delphi-binary-data-storage/

vu8f3i0k

vu8f3i0k1#

Delphi 为此提供了TIntegerSet,它具有整数的大小,因此可以在其上进行转换。

var
  Bits: TIntegerSet;
  IntVal: Integer;
begin
  if Value then
    Include(Bits, ItemNumber)
  else
    Exclude(Bits, ItemNumber);

  if ItemNumber in Bits then
    { Bit ItemNumber is set }
  else
    { Bit ItemNumber is not set } 

  { cast to Integer as needed }
  IntVal := Integer(Bits);

  { or from Integer }
  Bits := TIntegerSet(IntVal);

end;

对于一个字节中的8位,可以用类似的方式声明TByteSet

type 
  TByteSet = set of 0..7;

并将其转换为Byte变量或从Byte变量转换。

e4eetjau

e4eetjau2#

此类型实现任意大小的位集。

type
  TBitSet = record
  private
    FBitCount: Integer;
    FSets: array of set of 0..255;
    class function SetCount(BitCount: Integer): Integer; static;
    procedure MakeUnique;
    procedure GetSetIndexAndBitIndex(Bit: Integer; out SetIndex, BitIndex: Integer);
    function GetIsEmpty: Boolean;
    procedure SetBitCount(Value: Integer);
    function GetSize: Integer;
  public
    class operator In(const Bit: Integer; const BitSet: TBitSet): Boolean;
    class operator Equal(const bs1, bs2: TBitSet): Boolean;
    class operator NotEqual(const bs1, bs2: TBitSet): Boolean;
    class function SizeOfNativeSet(BitCount: Integer): Integer; static;
    property BitCount: Integer read FBitCount write SetBitCount;
    property Size: Integer read GetSize;
    property IsEmpty: Boolean read GetIsEmpty;
    procedure Clear;
    procedure IncludeAll;
    procedure Include(const Bit: Integer);
    procedure Exclude(const Bit: Integer);
  end;

{ TBitSet }

procedure TBitSet.MakeUnique;
begin
  // this is used to implement copy-on-write so that the type behaves like a value
  SetLength(FSets, Length(FSets));
end;

procedure TBitSet.GetSetIndexAndBitIndex(Bit: Integer; out SetIndex, BitIndex: Integer);
begin
  Assert(InRange(Bit, 0, FBitCount-1));
  SetIndex := Bit shr 8;   // shr 8   = div 256
  BitIndex := Bit and 255; // and 255 = mod 256
end;

function TBitSet.GetIsEmpty: Boolean;
var
  i: Integer;
begin
  for i := 0 to High(FSets) do begin
    if FSets[i]<>[] then begin
      Result := False;
      Exit;
    end;
  end;

  Result := True;
end;

procedure TBitSet.SetBitCount(Value: Integer);
var
  Bit, SetIndex, BitIndex: Integer;
begin
  if (Value<>FBitCount) or not Assigned(FSets) then begin
    Assert(Value>=0);
    FBitCount := Value;
    SetLength(FSets, SetCount(Value));
    if Value>0 then begin
      (* Ensure that unused bits are cleared, necessary give the CompareMem call in Equal. This also
         means that state does not persist when we decrease and then increase BitCount. For instance,
         consider this code:
           var
             bs: TBitSet;
           ...
           bs.BitCount := 2;
           bs.Include(1);
           bs.BitCount := 1;
           bs.BitCount := 2;
           Assert(not (1 in bs)); *)
      GetSetIndexAndBitIndex(Value - 1, SetIndex, BitIndex);
      for Bit := BitIndex + 1 to 255 do begin
        System.Exclude(FSets[SetIndex], Bit);
      end;
    end;
  end;
end;

function TBitSet.GetSize: Integer;
begin
  Result := Length(FSets)*SizeOf(FSets[0]);
end;

class function TBitSet.SetCount(BitCount: Integer): Integer;
begin
  Result := (BitCount + 255) shr 8; // shr 8 = div 256
end;

class function TBitSet.SizeOfNativeSet(BitCount: Integer): Integer;
begin
  Result := (BitCount + 7) shr 3; // shr 3 = div 8
end;

class operator TBitSet.In(const Bit: Integer; const BitSet: TBitSet): Boolean;
var
  SetIndex, BitIndex: Integer;
begin
  BitSet.GetSetIndexAndBitIndex(Bit, SetIndex, BitIndex);
  Result := BitIndex in BitSet.FSets[SetIndex];
end;

class operator TBitSet.Equal(const bs1, bs2: TBitSet): Boolean;
begin
  Result := (bs1.FBitCount=bs2.FBitCount)
    and CompareMem(Pointer(bs1.FSets), Pointer(bs2.FSets), bs1.Size);
end;

class operator TBitSet.NotEqual(const bs1, bs2: TBitSet): Boolean;
begin
  Result := not (bs1=bs2);
end;

procedure TBitSet.Clear;
var
  i: Integer;
begin
  MakeUnique;
  for i := 0 to High(FSets) do begin
    FSets[i] := [];
  end;
end;

procedure TBitSet.IncludeAll;
var
  i: Integer;
begin
  for i := 0 to BitCount-1 do begin
    Include(i);
  end;
end;

procedure TBitSet.Include(const Bit: Integer);
var
  SetIndex, BitIndex: Integer;
begin
  MakeUnique;
  GetSetIndexAndBitIndex(Bit, SetIndex, BitIndex);
  System.Include(FSets[SetIndex], BitIndex);
end;

procedure TBitSet.Exclude(const Bit: Integer);
var
  SetIndex, BitIndex: Integer;
begin
  MakeUnique;
  GetSetIndexAndBitIndex(Bit, SetIndex, BitIndex);
  System.Exclude(FSets[SetIndex], BitIndex);
end;
vojdkbi0

vojdkbi03#

这是一个简单的二进制逻辑。你可以用任何数字类型存储数据,但我建议使用无符号类型。这里是BYTE类型的示例,但你可以对任何(UInt16,UInt32,UInt64)写相同的内容,只需改变AStorage参数的类型:

//for byte Index can be from 0 to 7
function GetByteBool(const AStorage : byte; AIndex : byte) : boolean;
begin
  Result := (AStorage and (1 shl AIndex)) = (1 shl AIndex);
end;

procedure SetByteBool(var AStorage : byte; const AIndex : byte; const AValue : boolean);
begin
  if AValue then begin
    AStorage := AStorage or (1 shl AIndex);
  end else begin
    AStorage := AStorage xor (1 shl AIndex);
  end;
end;

procedure TForm2.Button1Click(Sender: TObject);
begin
  var b : byte := 17;

  SetByteBool(b, 4, false);

  if GetByteBool(b, 4) then
    showmessage('true')
  else
    showmessage('false')
end;

在这种情况下,每个布尔值只使用1个比特。

相关问题