2016-02-04 62 views
0

我为整型变量分配对象和整数值:如何检查对象是否被分配到一个整数变量

MyIntegerValue := Integer(MyObject); 
MyIntegerValue := 2; 
MyIntegerValue := 500; 
... 

如何检查是否MyIntegerValue已经分配了一个有效的对象?

+2

[TValue](http://docwiki.embarcadero.com/Libraries/en/System.Rtti.TValue)可以同时存放整数类型和类实例。没有安全的方式来说你的整数指向一个实例化的类。 –

+2

最简单的方法是**不要那么做**,因为这很愚蠢。不要混合整数和对象,并且你没有这个问题。严重的是,当你开始不得不提出这样的问题时,这是一个非常强烈的迹象表明你已经做了一件完全错误的事情,而摆脱这种情况的最好方式就是停止做那样做的事情,那样做是错误的,以至于你不得不问这个问题。 –

回答

8

如何检查MyIntegerValue是否已分配有效对象?

你不行。没有数据位来指示Integer正在持有什么。一个指针(不管它指向什么)只是一个数字,就CPU而言。它恰好是代表内存地址的数字。

此外,您尝试一个对象指针存储在一个Integer不会在64位系统的工作,你就需要使用NativeInt/NativeUInt代替,否则你将截断指针值。

要做你在问什么,你将不得不使用另一个变量来表示Integer值代表什么。或者更好的是,使用知道它所持有的容器类型,如TValueVariant(是的,您可以将对象指针存储在Variant中,但有一些工作)。

1

你无法可靠地做到这一点,你不应该试图在德尔福智胜型安全。


澄清:凭借可靠的我指的是以下情况:

您赋给变量的整数。然后,稍后您回来并想确定它是整数还是对象引用。您可能会试图通过调查指向的内存块来检查它是否为对象引用。您可能会看到结构和数据显示为Free Consulting。阿哈,你想,我已经存储了一个对象引用!但是,实际上您确实存储了一个整数,它的值恰好与对象的地址一致。

您指定一个有效对象引用,后来该对象被释放,而内存是什么重用。您检查内存结构等对象失败,并得出错误的结论,即您存储了整数。

4

自从very first comment向您提问以外,您应该关注有关类型安全性和类型转换的内容。我不会重复这一点,并专注于具体问题的实际方法。这也将讨论限制在32位目标上(因为你的问题假设为SizeOf(Integer) = SizeOf(Pointer));

首先,因为对象是指针(当你从对方回复得知),其平台强加的特性可以帮助真正的指针(有效!)和整数值来区分。看看Windows如何告诉字符指针列举值之外:

function Is_IntResource(lpszType: PChar): BOOL; 
begin 
    Result := ULONG_PTR(lpszType) shr 16 = 0; 
end; 

这利用了什么没有用户模式数据可以在低内存区域在32位Windows平台上进行分配,并因此事实,不存在有效的指针值p < 65536

接下来,可以使用对象的实例的Delphi专用内部数据格式,以检查是否指针是一个真正的对象实例:

/// <summary> 
/// Verifies that the argument points to valid object instance. 
/// </summary> 
/// <exception cref="EAccessViolation"> 
/// If segmentation fault occurs while attempting to read VMT and/or its 
/// field from the specified memory address. 
/// </exception> 
/// <remarks> 
/// Delphi only, incompatible with FPC. 
/// </remarks> 
/// <example> 
/// <code lang="Delphi"> 
///  procedure TForm1.FormCreate(Sender: TObject); 
///  begin 
///  ShowMessage(BoolToStr(IsInstance(Self), True)); 
///  end; 
/// </code> 
/// </example> 
function IsInstance(Data: Pointer): Boolean; 
var 
    VMT: Pointer; 
begin 
    VMT := PPointer(Data)^; 
    Result := PPointer(PByte(VMT) + vmtSelfPtr)^ = VMT; 
end; 

此功能检查V irtual 中号 ethod Ť能够用于Delphi RTL的签名和(给定内存读取操作成功并且签名检查通过)将任意指针标识为TObject(或后代)实例。

nil/0:你需要花约0指针值一个更加特殊的预防措施,因为它是作为Pointer非常有意义的,也是常见的Integer

+0

此外,IIRC 32位Windows在地址空间的顶部还保留了内存区域,这意味着也可以识别小的负值。 –

+0

+1 [内部数据格式(德尔福) - 类类型](http://docwiki.embarcadero.com/RADStudio/Seattle/en/Internal_Data_Formats#Class_Types)用于VMT引用 - 请参阅'vmtSelfPtr'常量 – fantaghirocco

相关问题