2013-02-28 45 views
8
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. 

上面会输出代码:为什么将单个变量分配给VarDouble变体会导致varDouble变体?

VARTYPE:单:5,双5

从System.pas

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

因此,我期望VTSingle到是 - 不是5
我错过了什么?

回答

5

Delphi库选择通过调用_VarFromReal来实现对变体的所有浮点赋值。这功能看起来像这样:

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的别名。我不知道为什么设计师选择了这种特定的路线,但是选择的结果就是你观察到的行为。

一个简单的方法,使varSingle变种,您可以使用:

VariantSingle := VarAsType(SingleTest, varSingle); 

虽然这SingleTest转换为Double,然后再次回到Single

为了避免这种不必要的转换,写了自己的助手:

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

,你可以这样调用:

VariantSingle := VarFromSingle(SingleTest); 

这后一种方法在我看来,正确的解决方案。

+0

你是否将'_VarFromReal'程序从asm翻译成了Pascal?至少在Delphi 2009中,它是作为一个'asm'程序来实现的。 – 2013-02-28 11:11:15

+0

@AndreasRejbrand现代Delphis还拥有Pascal版本,以利于新的非x86目标。所以我在这里使用了Pascal版本。 – 2013-02-28 11:13:36

相关问题