工作代码是:
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
我有两个问题:
我的理解是VB运行时在超出范围时释放了Long1和Long2的内存。为什么Debug.Print VarPtr(Long1)
在程序的每次运行中都返回相同的地址? VB Runtime是否为变量保留了内存的某个部分?我是这么认为的,因为即使我做了一些事情(例如关闭Chrome标签页)来从堆中释放内存,它也会显示相同的地址。
为什么我需要使用ByVal
来获得正确的结果?我确实理解CopyMemory
只是将整数VarPtr(Long1)
指向的地址中的一些字节移动到整数{{指向的地址。 1}},但我不知道为什么我必须使用关键字VarPtr(Long2)
,否则它只返回ByVal
。我认为也许VBA默认使用0
,而使用ByRef
它意味着从存储ByRef
地址的地址复制字节(基本上是对VarPtr返回值的引用)这只是一个整数),对于存储Long1
地址的地址来说,这不算什么。但是如果我故意使用Long2
,VBA只会给我错误信息。
答案 0 :(得分:1)
原始局部变量存储在stack上,因此地址取决于您调用例程的顺序,您可以通过一个简单的示例看到:
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初始化它)。
调用ByVal
时CopyMemory
关键字:我假设对VarPtr
的调用返回指针,并传递指针< / em>作为值 - 否则你将传递指针的地址。