如何获取给定变体的实际类型的内存大小?
How to get the memory size of the actual type of a given variant?
考虑以下代码:
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
)。
如何获取给定变体的实际类型的内存大小?
如果您的变量是 variant
,它将在 Win32 下使用(至少)16 个字节,在 Win64 下使用 24 个字节,无论存储什么值。
这个变量的内存大小总是variant
结构之一,在System.pas
中定义为TVarData
.
正在定义:
var
IntVariant: Variant;
实际上与定义相同:
var
IntVariant: TVarData;
有一些initialization/finalization魔法:
var
IntVariant: TVarData;
begin
IntVariant.VType := varEmpty;
try
...
finally
VarClear(variant(IntVariant));
end;
end;
如果您不存储任何内容(varEmpty
或 varNull
),它仍将使用 16/24 字节。如果您存储 boolean
,它仍将使用 16/24 字节。如果它存储一些 string
,则必须将堆分配的存储文本值添加到 16/24 字节。
您可以创建这样的函数:
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
将屏蔽定义变体数组的位。如果基本变体是数组类型,则屏蔽它会告诉您数组元素的类型。
您可以阅读更多内容in the documentation。
变体在幕后存储在 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;
考虑以下代码:
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
)。
如何获取给定变体的实际类型的内存大小?
如果您的变量是 variant
,它将在 Win32 下使用(至少)16 个字节,在 Win64 下使用 24 个字节,无论存储什么值。
这个变量的内存大小总是variant
结构之一,在System.pas
中定义为TVarData
.
正在定义:
var
IntVariant: Variant;
实际上与定义相同:
var
IntVariant: TVarData;
有一些initialization/finalization魔法:
var
IntVariant: TVarData;
begin
IntVariant.VType := varEmpty;
try
...
finally
VarClear(variant(IntVariant));
end;
end;
如果您不存储任何内容(varEmpty
或 varNull
),它仍将使用 16/24 字节。如果您存储 boolean
,它仍将使用 16/24 字节。如果它存储一些 string
,则必须将堆分配的存储文本值添加到 16/24 字节。
您可以创建这样的函数:
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
将屏蔽定义变体数组的位。如果基本变体是数组类型,则屏蔽它会告诉您数组元素的类型。
您可以阅读更多内容in the documentation。
变体在幕后存储在 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;