【问题标题】:Function to convert Integer to Packed Record of booleans?将整数转换为布尔值的打包记录的函数?
【发布时间】:2021-08-29 09:50:28
【问题描述】:

尝试将整数转换为 32 个布尔值的压缩记录。

 TUserRightsRecord = packed record
    r1:boolean;
    .
    .

 end;

然而,我找不到将变量转换为打包记录的函数,因为直接赋值不起作用。

  • 什么函数将变量(或至少整数)转换为相同字节大小的打包记录?

【问题讨论】:

  • SizeOf(Boolean) 不是 1/8,而是 1:Boolean 是一个字节(8 位)。无论如何:你为什么需要这个?为什么不像其他人一样使用按位运算?
  • 你能举个例子给我一些想法吗?你有什么建议?
  • const HasScreen = 1; HasSound = 2; HasKeyboard = 4; HasMouse = 8; HasInternet = 16; var ComputerProperties: Integer; // Test a bit if ComputerProperties and HasInternet = 0 then ShowMessage('You need an Internet connection.'); // Set a bit Computer := Computer or HasInternet; // Clear a bit Computer := Computer and not HasInternet; 但在 Delphi 中,您通常使用 sets 代替。
  • 希望得到更优雅的东西,比如 c++ 中 struct 的 typedef union :'|

标签: delphi


【解决方案1】:

尝试将整数转换为 32 个布尔值的压缩记录。

请注意SizeOf(Integer) = 4SizeOf(<packed record of 32 booleans>) = 32 因为SizeOf(Boolean) = 1(1 字节 = 8 位)。您似乎认为Boolean 是一个位;不是。

但是,如果是这种情况,您可以简单地将整数转换为这样的记录。

(当然,编写一个将整数“转换”为 32 个布尔值的记录的函数是很可能的。)


在整数中使用位的标准方法是使用位运算符:

const
  HasScreen = 1;
  HasSound = 2;
  HasKeyboard = 4;
  HasMouse = 8;
  HasInternet = 16;

var
  ComputerProperties: Integer;

begin
  // Test a bit
  if ComputerProperties and HasInternet = 0 then
    ShowMessage('You need an Internet connection.');

  // Set a bit
  Computer := Computer or HasInternet;

  // Clear a bit
  Computer := Computer and not HasInternet;

在Delphi中,使用sets更为惯用:

type
  TComputerFeature = (cfScreen, cfSound, cfKeyboard, cfMouse, cfInternet);
  TComputerFeatures = set of TComputerFeature;

var
  Features: TComputerFeatures;

begin
  Features := [cfScreen, cfKeyboard];
  if not (cfInternet in Features) then
    ShowMessage('You need an Internet connection.');
  Include(Features, cfInternet);
  Exclude(Features, cfInternet);
end;

但是,您可以使用高级记录轻松模拟您的原始设计方法:

type
  TBit32 = type Integer;
  TBit32Helper = record helper for TBit32
  strict private
    function GetBit(Index: Integer): Boolean;
    procedure SetBit(Index: Integer; const Value: Boolean);
  public
    property Bit[Index: Integer]: Boolean read GetBit write SetBit;
  end;

function TBit32Helper.GetBit(Index: Integer): Boolean;
begin
  Result := (Self shr Index) and 1 <> 0;
end;

procedure TBit32Helper.SetBit(Index: Integer; const Value: Boolean);
begin
  if Value then
    Self := Self or (1 shl Index)
  else
    Self := Self and not (1 shl Index);
end;

begin
  var x: Integer := 123;
  Writeln(TBit32(x).Bit[4]); // read
  TBit32(x).Bit[6] := False; // write

【讨论】:

    【解决方案2】:

    用 longbool 代替 boolean 可能就足够了

    program Project1;
    {$APPTYPE CONSOLE}
    {$R *.res}
    
    uses
     System.SysUtils;
    var
      i: integer;
    begin
     try
       i := Sizeof(boolean);
       writeln('Sizeof(boolean): ', i);
    
       i := Sizeof(LongBool);
       writeln('Sizeof(LongBool): ', i);
    
       readln(i);
    
     except
       on E: Exception do
         Writeln(E.ClassName, ': ', E.Message);
     end;
    end.
    

    否则,您可能必须将自己的数据类型定义为记录。这里你要注意你的数据类型“SizeOf”的内存大小。举个例子:

    program Project1;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      System.SysUtils;
    
    type
      TConvert=packed record
      public
        function ToString: string;
      public
        //Redefined memory. Each field has the same start address.
        case integer of
          0: (b: boolean);
          1: (G: LongBool);
          2: (i: integer);
          3: (data: array[0..3]of byte);
      end;
    
    function TConvert.ToString: string;
    begin
      //Low is left !!!
      Result := Format('[%.2x|%.2x|%.2x|%.2x]', [data[0], data[1], data[2], data[3]]);
    end;
    
    var
      i: integer;
      r: TConvert;
    begin
      try
        i := Sizeof(TConvert);
        writeln('Sizeof(TConvert): ', i);
    
    r.b := True;
    writeln('boolean(true): ', r.ToString, ' ',BoolToStr(r.G, true));
    r.G := false;
    writeln('LongBool(false): ', r.ToString, ' ',BoolToStr(r.G, true));
    r.G := True;
    writeln('LongBool(true): ', r.ToString, ' ',BoolToStr(r.G, true));
    r.i := 1;
    writeln('LongBool(i=1): ', r.ToString, ' ',BoolToStr(r.G, true));
    
    
    readln(i);
    
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
    end.
    

    【讨论】:

    • 在我看来你误解了这个问题。 LongBool 肯定不是一点点。
    • SizeOf( LongBool ) 应该是 32 位,而不是 1。
    猜你喜欢
    • 1970-01-01
    • 2013-12-03
    • 2014-09-03
    • 1970-01-01
    • 2014-01-20
    • 2019-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多