如何获得给定变量的实际类型的内存大小



考虑以下代码:

procedure Test;
var
  IntGenuine: UInt64;
  IntVariant: Variant;
begin
  IntGenuine := 0;
  IntVariant := UInt64(0); // The type of the variant is UInt64 now
  WriteLn('Size of IntGenuine = ', SizeOf(IntGenuine)); // Output: 8
  WriteLn('Size of IntVariant = ', SizeOf(IntVariant)); // Output: 24
end;

我知道表述SizeOf(IntVariant)等价于SizeOf(Variant)。它获得类型Variant的大小,而不是变体的实际类型(在本例中为UInt64)的大小。

如何获得给定变量的实际类型的内存大小?

你可以这样创建一个函数:

Program Project1;
{$APPTYPE CONSOLE}
uses
  Variants, SysUtils;
function GetVarTypeSize(AVarType : TVarType; var isArray : boolean) : integer;
begin
  isArray := AVarType <> (AVarType and VarTypeMask);    
  case AVarType and VarTypeMask of
    varSmallInt: result := SizeOf(SmallInt);
    varInteger:  result := SizeOf(Integer);
    varSingle:   result := SizeOf(Single);
    varDouble:   result := SizeOf(Double);
    varCurrency: result := SizeOf(Currency);
    varDate:     result := SizeOf(TDateTime);
    varOleStr:   result := SizeOf(PWideChar);
    varDispatch: result := SizeOf(Pointer);
    varError:    result := SizeOf(HRESULT);
    varBoolean:  result := SizeOf(WordBool);
    varUnknown:  result := SizeOf(Pointer);
    varShortInt: result := SizeOf(ShortInt);
    varByte:     result := SizeOf(Byte);
    varWord:     result := SizeOf(Word);
    varLongWord: result := SizeOf(LongWord);
    varInt64:    result := SizeOf(Int64);
    varUInt64:   result := SizeOf(UInt64);
    varString:   result := SizeOf(Pointer);
    varAny:      result := SizeOf(Pointer);
    varArray:    result := SizeOf(PVarArray);
    varByRef:    result := SizeOf(Pointer);
    varUString:  result := SizeOf(Pointer);
    varRecord:   result := SizeOf(TVarRecord);
  else
    result := -1;  //unknown
  end;
end;
var
  v : Variant;
  b : boolean;
begin
  v := 3.141592654;   // double
  Write(GetVarTypeSize(VarType(v), b));
  if b then WriteLn(' : Is array') else WriteLn;
  v := 3;             // byte
  Write(GetVarTypeSize(VarType(v), b));
  if b then WriteLn(' : Is array') else WriteLn;
  v := integer(3);    // integer
  Write(GetVarTypeSize(VarType(v), b));
  if b then WriteLn(' : Is array') else WriteLn;
  v := Now;           // DateTime
  Write(GetVarTypeSize(VarType(v), b));
  if b then WriteLn(' : Is array') else WriteLn;
  v := VarArrayCreate([0,9], varDouble);   //array ! careful
  Write(GetVarTypeSize(VarType(v), b));
  if b then WriteLn(' : Is array') else WriteLn;
  ReadLn;
end.

这里VarTypeMask将屏蔽定义变量数组的位。如果基本变量是数组类型,屏蔽它将告诉您数组元素的类型。

您可以在文档中阅读更多内容

如果你的变量是variant,它将使用(至少)16个字节在Win32下,和24个字节在Win64下,无论存储的值

该变量的内存大小始终是variant结构体的内存大小,在System.pas中定义为TVarData

定义:

var
  IntVariant: Variant;

实际上等同于定义:

var
  IntVariant: TVarData;

带有一些初始化/终结化魔法:

var
  IntVariant: TVarData;
begin
  IntVariant.VType := varEmpty;
  try
    ...
  finally
    VarClear(variant(IntVariant));
  end;
end;

如果您不存储任何内容(varEmptyvarNull),它仍将使用16/24字节。如果存储boolean,它仍然会使用16/24字节。如果它存储一些string,则必须将堆分配的存储文本值添加到16/24字节。

在后台,变量存储在类型为TVarData的记录中。

系统。TVarData记录:

PVarData = ^TVarData;
TVarData = packed record
  case Integer of
    0: (VType: TVarType;
        case Integer of
          0: (Reserved1: Word;
              case Integer of
                0: (Reserved2, Reserved3: Word;
                    case Integer of
                      varSmallInt: (VSmallInt: SmallInt);
                      varInteger:  (VInteger: Integer);
                      varSingle:   (VSingle: Single);
                      varDouble:   (VDouble: Double);
                      varCurrency: (VCurrency: Currency);
                      varDate:     (VDate: TDateTime);
                      varOleStr:   (VOleStr: PWideChar);
                      varDispatch: (VDispatch: Pointer);
                      varError:    (VError: HRESULT);
                      varBoolean:  (VBoolean: WordBool);
                      varUnknown:  (VUnknown: Pointer);
                      varShortInt: (VShortInt: ShortInt);
                      varByte:     (VByte: Byte);
                      varWord:     (VWord: Word);
                      varLongWord: (VLongWord: LongWord);
                      varInt64:    (VInt64: Int64);
                      varUInt64:   (VUInt64: UInt64);
                      varString:   (VString: Pointer);
                      varAny:      (VAny: Pointer);
                      varArray:    (VArray: PVarArray);
                      varByRef:    (VPointer: Pointer);
                      varUString:  (VUString: Pointer);
                      varRecord:   (VRecord: TVarRecord);
                      //$ffff:     (VLargest: TLargestVarData);
                   );
                1: (VLongs: array[0..{$IFDEF CPUX64}4{$ELSE}2{$ENDIF}] of LongInt);
             );
          2: (VWords: array [0..{$IFDEF CPUX64}10{$ELSE}6{$ENDIF}] of Word);
          3: (VBytes: array [0..{$IFDEF CPUX64}21{$ELSE}13{$ENDIF}] of Byte);
        );
    1: (RawData: array [0..{$IFDEF CPUX64}5{$ELSE}3{$ENDIF}] of LongInt);
end;

您正在寻找的信息可以将Variant变量转换为以下类型:

var
  varData: TVarData;
  intVariant: Variant;
  size: Integer;
begin
  intVariant := UInt64(10);
  varData := TVarData(IntVariant);
  case varData.VType of
    varUInt64: size := SizeOf(varData.VUInt64);
    varInteger: size := SizeOf(varData.VInteger);
  . . .
  end;
end;

…但以上并不是通常的做法:

var
  intVariant: Variant;
  size: Integer;
  vType: Integer;
begin     
  vType := VarType(intVariant) and VarTypeMask;
  case vType of
    varUInt64: size := SizeOf(UInt64);
    varInteger: size := SizeOf(Integer);
    . . .
  end;
end;

相关内容

  • 没有找到相关文章

最新更新