Why does assigning one variant to a variant result in a varDouble?

uses SysUtils, Variants; var VariantSingle: Variant; VTSingle: TVarType; SingleTest: Single; VariantDouble: Variant; DoubleTest: Double; VTDouble: TVarType; begin SingleTest := 1.234; VariantSingle := SingleTest; VTSingle := VarType(VariantSingle) and varTypeMask; DoubleTest := 1.23456; VariantDouble := DoubleTest; VTDouble := VarType(VariantDouble) and varTypeMask; WriteLn(Format('VarType: Single: %d, Double %d', [VTSingle, VTDouble])); end. 

The above code outputs:

VarType: Single: 5, Double 5

From System.pas

 varSingle = $0004; { vt_r4 4 } varDouble = $0005; { vt_r8 5 } 

So I would expect VTSingle to be 4 - not 5
What am I missing?

+8
delphi variant
source share
1 answer

In Delphi libraries, it is proposed to implement all floating point assignments for options using the _VarFromReal call. And this function looks like this:

 procedure _VarFromReal(var V: TVarData; const Value: Real); begin if (V.VType and varDeepData) <> 0 then VarClearDeep(V); V.VType := varDouble; V.VDouble := Value; end; 

Note that the varDouble type is used for this. And includes an implicit conversion to Real , which is an alias for Double . I'm not sure why the designers chose this particular route, but the consequence of this choice is the behavior that you observe.

An easy way to make a varSingle variant that you can use:

 VariantSingle := VarAsType(SingleTest, varSingle); 

Although this converts SingleTest to Double and then back to Single .

To avoid unnecessary conversion, write your own helper:

 function VarFromSingle(const Value: Single): Variant; begin VarClear(Result); TVarData(Result).VSingle := Value; TVarData(Result).VType := varSingle; end; 

which you can call as follows:

 VariantSingle := VarFromSingle(SingleTest); 

This last approach is the right solution, in my opinion.

+5
source share

All Articles