如何检查对象是否已分配给整型变量

How to check if an object has been assigned to an integer variable

我正在将对象和整数值分配给一个整数变量:

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

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

你不能可靠地做到这一点,你不应该试图超越 Delphi 中的类型安全。


澄清一下:我指的是以下情况:

您将 整数 分配给变量。然后,稍后您回来并想要确定它是整数还是对象引用。您可能会想首先通过调查指向的内存块来检查它是否是对象引用。您可能会看到 Free Consulting 所示的结构和数据。啊哈,你认为,我已经存储了一个对象引用!然而,你实际上存储了一个整数,它的值恰好与对象的地址重合。

您分配了一个有效的 对象 引用,稍后对象被释放并且内存被重新用于任何事情。您对诸如内存结构之类的对象的检查失败,并得出错误的结论,即您存储了一个整数。

How to check if MyIntegerValue has been assigned with a valid object?

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

此外,您尝试在 Integer 中存储对象指针的尝试在 64 位系统上不起作用,您需要使用 NativeInt/NativeUInt,否则您将截断指针值。

要执行您要求的操作,您必须使用另一个变量来指示 Integer 值代表什么。或者更好的是,使用知道它持有什么的容器类型,例如 TValueVariant(是的,您可以通过一些工作将对象指针存储在 Variant 中)。

您应该注意自 向您提问以来关于类型安全和类型转换的讨论。我不会重复这一点,而是专注于解决具体问题的实用方法。这也将讨论限制在 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虚拟M方法T能够为[=47签名=] RTL 和(给定内存读取操作成功且签名检查通过)将任意指针识别为 TObject(或后代)实例。

nil/0:您需要对 0 指针值采取更加特别的预防措施,因为它与 Pointer 一样非常有意义并且也很常见Integer.