6

奇怪的观察:

通常,当我想将地址保存到变量中的函数时,我会执行以下操作:

Function getAddress(ByVal func As LongPtr) As LongPtr
    getAddress = func
End Function

Sub printAddress()
    Dim functionPointer As LongPtr
    functionPointer = getAddress(AddressOf myFunc)
    Debug.Print functionPointer
End Sub

但是我刚刚发现我可以使用 1-liner

functionPointer = VBA.CLngPtr(AddressOf myFunc)

尽管

functionPointer = CLngPtr(AddressOf myFunc)

...不起作用并引发

编译错误:

预期:表达式

这是怎么回事?据我所知,唯一的区别是它CLngPtr是在全局变量(类?)中声明的,而VBA.CLngPtr它是明确限定的,但我不知道为什么这会导致观察到的行为(它们都指向同一个函数)他们?)

4

2 回答 2

4

如果您使用默认的 IDE 设置,而关键字和标识符的设置并没有那么不同,这将不是很明显。以下是使用不同颜色时的外观: 示例代码

您可以看到它CLngPtr像圣诞树一样亮起,看起来就像任何其他关键字一样。将此与 比较Abs,它也是一个函数,但保持浅蓝色,就好像它只是一个标识符。

这是一个由 VBA 编译器优化的提示,CLngPtr因此它实际上是内联方法1,这就是如果您尝试将其CLngPtr用作表达式会出错的原因。但是,aVBA.CLngPtr是一个适当的函数,因此可以用作表达式的一部分,但由于非优化路线而具有非常轻微的性能损失。

你会看到同样的东西,CLng或者任何转换函数,甚至Mid语句(不是函数)。其中有几个函数VBA可能会被编译器内联,并且通常会因它们是否变成关键字而有所不同。另请注意,括号的颜色不同。

哎呀,甚至也Debug.Print得到了特殊待遇,如果你熟悉它,你可能知道它不完全是一个类也不是一个模块,但你不能Print没有Debug.


  1. 当我们在这里提到“内联”时,我们谈论的是 VBA 编译器在较低级别执行的操作,低于我们在源代码级别看到的。从源代码来看,C***()VBA.C***()基本上是一回事。但是,VBA 编译器可以并且将尝试通过内部重新排列机器指令以进行转换(或内联函数正在执行的任何操作)来优化这些位。重新排列指令的效果是它可能不再在所有上下文中兼容。在这种情况下,我可以想象(但不知道事实!)CLngPtr()内联指令返回一个值,而不是一个引用,这与参数声明不兼容,这就是为什么我们在尝试时会遇到语法错误将其用作参数。请注意,这不会发生AddressOfAddressOf-- LHS 上的任何其他函数都会有相同的语法错误,因此它与内联方法无关。
于 2019-08-07T14:28:05.240 回答
0

不是答案,而是更奇怪的思考......

使用注释中指出的编译错误,这有效(参考):

Sub TestCasting()
    Dim value As Variant
    Debug.Print "value cast with     CBool  : " & CBool(value)
    Debug.Print "value cast with VBA.CBool  : " & VBA.CBool(value)

    Debug.Print "value cast with     CByte  : " & CByte(value)
    Debug.Print "value cast with VBA.CByte  : " & VBA.CByte(value)

    Debug.Print "value cast with     CCur   : " & CCur(value)
    Debug.Print "value cast with VBA.CCur   : " & VBA.CCur(value)

    Debug.Print "value cast with     CDate  : " & CDate(value)
    Debug.Print "value cast with VBA.CDate  : " & VBA.CDate(value)

    Debug.Print "value cast with     CDbl   : " & CDbl(value)
    Debug.Print "value cast with VBA.CDbl   : " & VBA.CDbl(value)

    Debug.Print "value cast with     CDec   : " & CDec(value)
    Debug.Print "value cast with VBA.CDec   : " & VBA.CDec(value)

    Debug.Print "value cast with     CInt   : " & CInt(value)
    Debug.Print "value cast with VBA.CInt   : " & VBA.CInt(value)

    Debug.Print "value cast with     CLng   : " & CLng(value)
    Debug.Print "value cast with VBA.CLng   : " & VBA.CLng(value)

    '--- Compile Error: Sub or Function not found
    '    (error displayed at run time)
    'Debug.Print "value cast with     CLngLng: " & CLngLng(value)
    'Debug.Print "value cast with VBA.CLngLng: " & VBA.CLngLng(value)

    Debug.Print "value cast with     CLngPtr: " & CLngPtr(value)
    Debug.Print "value cast with VBA.CLngPtr: " & VBA.CLngPtr(value)

    Debug.Print "value cast with     CSng   : " & CSng(value)
    Debug.Print "value cast with VBA.CSng   : " & VBA.CSng(value)

    Debug.Print "value cast with     CStr   : " & CStr(value)
    Debug.Print "value cast with VBA.CStr   : " & VBA.CStr(value)

    Debug.Print "value cast with     CVar   : " & CVar(value)
    Debug.Print "value cast with VBA.CVar   : " & VBA.CVar(value)

End Sub

并添加到上面的代码示例中:

Function myFunc() As String
    myFunc = "help!"
End Function

Function getAddress(ByVal func As LongPtr) As LongPtr
    getAddress = func
End Function

Sub printAddress()
    Dim functionPointer As LongPtr
    functionPointer = getAddress(AddressOf myFunc)
    Debug.Print functionPointer
    functionPointer = VBA.CLngPtr(AddressOf myFunc)

    '--- Compile Error: Syntax Error
    '    (error displayed in red in VBA Editor)
    'debug.Print CLngPtr(AddressOf myFunc)
    'functionPointer = CLngPtr(AddressOf myFunc)
    Debug.Print functionPointer
End Sub
于 2019-08-07T14:28:22.673 回答