工作代码是:
Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal ByteLen As Long)
Sub Test()
Dim Long1 As Long
Dim Long2 As Long
Long1 = 1000
CopyMemory ByVal VarPtr(Long2), ByVal VarPtr(Long1), 4
Debug.Print VarPtr(Long1)
Debug.Print Long2
End Sub
我有两个问题:
我的理解是,当 Long1 和 Long2 超出范围时,VB 运行时会释放它们的内存。为什么Debug.Print VarPtr(Long1)
在每次运行程序时都返回相同的地址?VB运行时是否为变量保留了内存的某一部分?我相信是的,因为即使我做了一些事情(例如关闭Chrome标签(来从它保持显示相同地址的堆中释放内存。
为什么我需要使用ByVal
才能获得正确的结果?我确实理解CopyMemory
只是将多个字节从整数VarPtr(Long1)
指向的地址移动到整数VarPtr(Long2)
指向的地址,但我不知道为什么我必须使用关键字ByVal
,否则它只会返回0
。我认为也许 VBA 默认ByRef
,并且ByRef
意味着将字节从存储Long1
地址的地址(基本上是对 VarPtr 返回值的引用,它只是一个整数(,这没什么,到存储Long2
地址的地址, 这也算不了什么。但是如果我故意使用ByRef
,VBA 只会给我错误消息。
原始局部变量存储在堆栈上,因此地址取决于您调用例程的顺序,您可以通过一个简单的示例看到这一点:
Sub showAdresses()
myTest
callTest
callTest
myTest
End Sub
Sub callTest()
myTest
End Sub
Sub myTest()
Dim x As Long
Debug.Print VarPtr(x)
End Sub
您将看到第一次和最后一次调用的相同地址,以及中间调用的另一个地址 - 仅仅是因为堆栈上需要空间用于中间例程。当子例程完成时,堆栈上消耗的空间被释放,并且(这是堆栈的性质(立即重用,因此,如果您再次调用相同的例程,相同的变量将获得相同的地址(但 VBA 会初始化它(。
对于调用CopyMemory
时的ByVal
关键字:我假设对VarPtr
的调用返回一个指针,并且您将指针作为值传递 - 否则您将传递指针的地址。