首先,我要夸奖一下您写出了这样一个经过深入研究的问题!基本上,您已经理解得很正确。在Delphi中,静态数组是值类型,就像单个整数或整数记录一样。使用
sizeof
操作符,可以获得数据的完整大小。另一方面,动态数组是引用类型。变量仅存储指向实际数组数据的单个指针。因此,在动态数组上使用
sizeof
操作符只会返回指针的大小。
当然,这也会影响赋值时发生的事情:如果您使用
a := b
操作符复制静态数组,则会复制所有数据,并且最终得到两个独立的数组。如果您复制动态数组,则只复制指针,并且最终得到两个指向相同数据的指针。
所以,回到您的代码:
Value1 := PUInt64(@MyArray1)^;
是的,因为
MyArray1
是以
100
开头的数据,所以
@MyArray1
是指向
100
值的指针。类型转换是正确的(因为数组中的数据类型是
UInt64
,指向该值的指针的类型是
PUInt64
),通过解引用,您可以得到
100
。
Value2 := PUInt64(@MyArray2)^;
是的,因为MyArray2
是实际数据的指针,所以@MyArray2
是指向实际数据指针的指针。在64位进程中,指针是64位整数,所以类型转换是有效的。通过取消引用,您可以获得返回实际数据的原始指针。但在32位进程中这样做是错误的。
更简单地说,您可以写成(*)
Value2 := NativeUInt(MyArray2);
让我们继续进行
Value1 := PUInt64(@MyArray1[0])^;
这很简单:
MyArray1 [0]
是你的
100
,你获取地址然后取消引用指针以获得原始值。
Value2 := PUInt64(@MyArray2[0])^;
我的想法完全相同。
而且
Value2 := PUInt64(MyArray2)^;
这基本上就是我在上面提到的情况(在*处),只不过它被解除引用了。它在32位和64位应用程序中都是有效的。(由于P的存在,PUInt64的大小为本地大小,可能为32位)。实际上,MyArray2是指向UInt64的指针,也就是PUInt64,因此通过解除引用它,您可以获得那个UInt64值(100)。
然而,
Value1 := PUInt64(MyArray1)^;
这是一个错误。在您的情况下,MyArray1
实际上与 UInt64
完全相同。它不是指向这样一个东西的指针,也不是 PUInt64
。当然,您可以欺骗编译器并告诉它:“嘿,把这个当作指向 UInt64
的指针来处理。” 但是通过对它进行解引用,您将尝试获取地址为 100
的 UInt64
值,这将导致访问冲突,因为您并没有拥有该内存区域(很可能)。
在 64 位进程中,代码会编译通过,因为大小匹配。PUInt64
的大小为指针大小(64 位),而按照您的声明,MyArray1
的大小为 64 位。
在 32 位进程中,代码无法编译通过,因为大小不匹配。PUInt64
的大小为指针大小(32 位),但是按照您的声明,MyArray1
的大小为 64 位。
此外,似乎 PUInt64(@MyArray2[0])^
是最安全的转换,因为它可以同时用于静态数组和动态数组。是这样吗?
通常,我觉得静态数组和动态数组是两个非常不同的东西,因此我不会试图强制让代码在两种情况下都看起来相同。
您是想获取数组中的第一个值吗?如果是,请直接写 MyArray2[0]
。(或者在静态数组的情况下写成 MyArray1[0]
。)您想获取第一个元素的地址吗?如果是,我更喜欢使用 NativeUInt(MyArray2)
,而不是 NativeUInt(@MyArray2[0])
(或者 pointer
、PUInt64
)。实际上,如果数组为空,则第一种方法会产生 0
或 nil
,而另一种方法则是错误。
更新:
要澄清一下,如果 a
是静态数组,则第一个元素的地址就是 @a
(或者 @a[0]
)。如果 b
是动态数组,则第一个元素的地址为 pointer(b)
(或者 @b[0]
)。您可以将任何指针转换为其他指针大小的类型,例如 NativeUInt
(整数类型)或 PUInt64
(特定指针类型)或 PCardinal
(特定指针类型)等。这不会改变实际值,只会改变编译时的解释。
Value1 := PUInt64(MyArray1[0])^;
替代Value1 := PUInt64(MyArray1)^;
。 - Schneider Infosystems LtdMyArray1[0]
是UInt64
,而不是指向UInt64
的指针(100
不是有效地址)。在 32 位进程中,大小甚至都不匹配(指针是 32 位的,但MyArray1[0]
是 64 位的)。 - Andreas RejbrandPUInt64(MyArray1[0])^
等于PUInt64(100)^
。这会导致在地址0x064(100)处发生读取访问冲突。 - Schneider Infosystems Ltd