【问题标题】:Assigning a Pointer to a NativeInt causes E2010 Incompatible types将指针分配给 NativeInt 会导致 E2010 不兼容的类型
【发布时间】:2020-09-28 09:01:33
【问题描述】:

Pointer 分配给NativeInt 变量会导致编译时出现E2010:

var
  Test : string;
  Ptr : Pointer;
  LocTag : NativeInt;
begin
  Test := 'Hello World';

  Ptr := @Test;
  LocTag := Ptr;
end;

[dcc32 错误] Unit1.pas(34): E2010 不兼容的类型:'NativeInt' 和 '指针'

我读过Pointerdocumentation,尤其是:

指针的大小取决于操作系统和/或 处理器。在 32 位平台上,指针存储在 4 个字节上作为 32 位地址。在 64 位平台上,指针存储在 8 个字节上 64 位地址。

还有NativeIntdocumentation,特别是:

NativeInt 表示整数的子集。的范围 NativeInt 取决于当前平台。在 32 位平台上, NativeInt 等价于 Integer 类型。在 64 位平台上, NativeInt 等价于 Int64 类型。

NativeInt 的大小相当于指针的大小 当前平台

为什么赋值会导致 E2010 错误?

类型转换 (Tag := NativeInt(Ptr);) 是正确的解决方案吗?

【问题讨论】:

  • 虽然有点离题,但可能值得指出的是,在实践中,您很少需要使用字符串S 中的@S。对PChar(S) 感兴趣更为常见,这与@S[1] 相同,除非S 为空。
  • 另一个题外话:如果 S 是一个字符串,那么 @S 和 PChar(S) 具有完全不同的值。字符串实际上是由具有几个字段的记录实现的。一个是指向字符串第一个字符的指针,或者字符串的 nil 为空。 @S 返回指向记录的指针,而 PChar(S) 返回记录中指向字符的字段(nil 为空字符串,@S[1] 如果不为空)。
  • @fpiette:实际上,这种描述并不准确。字符串变量是一个指针。如果字符串非空,则 this 指向字符串堆对象的第一个字符。在第一个字符之前,您有一些关于字符串的元数据:长度、引用计数和代码页。 @S 是指针的地址。 PChar(S) 是字符串堆对象的第一个字符的地址。如果S 是空字符串,则变量是nil 指针。 ...
  • (续)这里是an image,这里是documentation
  • 函数返回时字符串被销毁不是真正的问题,现在Tag持有一个过时的指针。

标签: pointers delphi delphi-xe7


【解决方案1】:

为什么赋值会导致 E2010 错误?

因为整数和指针并不完全相同。指针是指向你记忆中某个位置的东西。整数不需要这样做(即使它恰好与指针具有相同的大小)。这是关于类型安全并确保您不会犯错误。通过使用显式强制转换(您必须这样做),您可以告诉编译器、阅读您代码的任何人以及您自己,您知道自己在做什么。

类型转换 (Tag := NativeInt(Ptr);) 是正确的解决方案吗?

是的,这是正确的做法。它也是非常安全的,因为 (NativeInt) 整数的宽度等于指针的宽度。

【讨论】:

  • (好吧,如果你不对整数做任何愚蠢的事情,比如将它除以二,将商转换为PCardinal,并尝试写基数,那么它是“完全安全的” $AABBCCDD 到这个位置。)
【解决方案2】:

类型转换 (Tag := NativeInt(Ptr);) 是正确的解决方案吗?

它会起作用,但我认为最好使用 UIntPtr 类型,它被定义为表示一个无符号整数,其值为指针。 UIntPtr 用于将指针用作无符号整数。

如果您查看UIntPtr 的定义,它是NativeUInt 的别名。

还有一个IntPtr,它是NativeInt 的别名。这显然也有效。

使用UIntPtr 比其他任何方法都更清晰,如果您稍后使用该变量进行指针运算,则更合适。这避免了当指针指向高内存(在 32 位地址空间中超过 2GB)时出现意外结果,因为在这种情况下整数变为负数。

【讨论】:

  • 另一方面,VCL 的Tag 属性是NativeInt 类型。
  • +1 很有趣,我不知道IntPtr/UIntPtr 类型。就像 Andreas 所说,我想知道为什么 Tag 属性被声明为 NativeInt (可能是因为它不一定只用作指针)
  • @Fabrizio 实际上,Tag 属性可以是具有正确大小甚至更大大小的任何数据类型。数据类型仅在您想对数据执行某些操作时才重要。只要您想进行一些计算或使用,就必须将标记属性值转换为正确的数据类型。必须区分存储和计算。对于存储,任何大小等于或大于所需大小的东西都可以。对于计算,它取决于您想要执行的计算(我包括取消引用指向计算类的指针)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-29
  • 2018-11-17
  • 2014-06-27
  • 1970-01-01
相关资源
最近更新 更多