考虑以下代码:
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;
如果您不存储任何内容(varEmpty
或varNull
),它仍将使用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;