为什么将单个分配给变量会导致varDouble变量?

为什么将单个分配给变量会导致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.

上面的代码将输出:

VarType:单身:5,双身5

VarType: Single: 5, Double 5

从System.pas

From System.pas

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

因此,我希望VTSingle为 4 -而不是5
我想念什么?

Thus, I'd expect VTSingle to be 4 - not 5
What am I missing?

Delphi库选择通过调用_VarFromReal来实现对变量的所有浮点分配.该函数如下所示:

The Delphi libraries choose to implement all floating point assignments to variants by means of a call to _VarFromReal. And that 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;

请注意,这使用的是varDouble类型.并且包括对Real的隐式转换,这是Double的别名.我不确定为什么设计师会选择这种特定的路线,但是这种选择的结果就是您观察到的行为.

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

可以使用一种简单的方法来制作varSingle变体:

A simple way to make a varSingle variant you can use:

VariantSingle := VarAsType(SingleTest, varSingle);

尽管这会将SingleTest转换为Double,然后再次转换回Single.

Although this will convert SingleTest to Double, and then back again to Single.

为避免不必要的转换,请编写您自己的帮助器:

To avoid that needless conversion, write your own helper:

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

您可以这样称呼:

VariantSingle := VarFromSingle(SingleTest);

后一种方法在我看来是正确的解决方法.

This latter approach is the correct solution in my opinion.