我将对象和整数值分配给整数变量:
MyIntegerValue := Integer(MyObject);
MyIntegerValue := 2;
MyIntegerValue := 500;
...
如何检查MyIntegerValue是否已分配有效对象?
答案 0 :(得分:8)
如何检查MyIntegerValue是否已分配有效对象?
你做不到。没有数据位来指示Integer
持有的内容。指针(无论它指向什么)只是一个数字,就CPU而言。它恰好是一个代表内存地址的数字。
此外,您在Integer
中存储对象指针的尝试在64位系统上无效,您需要使用NativeInt
/ NativeUInt
,否则会截断指针值。
要执行您要求的操作,您必须使用另一个变量来指示Integer
值表示的内容。或者更好的是,使用一个容器类型,知道它持有什么,比如TValue
或Variant
(是的,您可以将对象指针存储在Variant
中,但有些工作)。
答案 1 :(得分: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;
此功能检查能够进行Delphi RTL签名的 V irtual M ethod T (给定内存读取操作成功并通过签名检查) )将任意指针标识为TObject
(或后代)实例。
nil
/ 0
:您需要对0
指针值采取更加特殊的预防措施,因为它与Pointer
非常有意义,并且与{{{{{{ 1}}。
答案 2 :(得分:1)
你无法可靠地做到这一点,你不应该试图超越德尔福的类型安全。
澄清:可靠我的意思是以下情况:
为变量指定整数。然后,稍后您回来并想确定它是整数还是对象引用。您可能想通过调查指向的内存块来首先检查它是否是对象引用。您可能会看到Free Consulting
显示的结构和数据。 Ahaa,你想,我已经存储了一个对象参考!但是,实际上你确实存储了一个整数,它的值恰好与一个对象的地址重合。
和
您指定了一个有效的对象引用,稍后释放该对象并重新使用该内存。检查内存结构等对象是否失败,并得出错误的结论,即存储了一个整数。