VBA:是什么导致传递给 ParamArray 的字符串参数更改为数字(看起来可疑地像指针)?

发布于 2024-09-12 05:08:47 字数 2175 浏览 2 评论 0原文

最终编辑:它确实似乎是一个编译器错误 - 请参阅已接受的答案。

在 Excel 2007 中使用 VBA,我在“Class1”中有以下代码:

Option Explicit

Public Function strange(dummy As String, ParamArray pa())
    Debug.Print pa(LBound(pa))
End Function

Public Sub not_strange(dummy As String, ParamArray pa())
    Debug.Print pa(LBound(pa))
End Sub

Public Function also_not_strange(ParamArray pa())
    Debug.Print pa(LBound(pa))
End Function

以及模块中的一些模式代码:

Option Explicit

Public Function not_strange_either(dummy As String, ParamArray pa())
    Debug.Print pa(LBound(pa))
End Function

Public Sub outer(v)
    Dim c As Class1
    Set c = New Class1

    Call c.strange("", v(LBound(v)))
    Call c.not_strange("", v(LBound(v)))
    Call c.also_not_strange(v(LBound(v)))

    Call not_strange_either("", v(LBound(v)))
End Sub

如果从“立即”窗口调用“外部”,如下所示:

call outer(array("a"))

我得到的输出看起来很奇怪:

 102085832 
a
a
a

似乎很重要被调用的例程是否在类模块中,无论它是 Sub 还是 Function,以及是否有初始参数。我是否遗漏了有关 VBA 应该如何工作的信息?有什么想法吗?

这个奇怪的数字在每次运行中都会发生变化。我说“看起来可疑地像一个指针”,因为如果我这样称呼:

Public Sub outer2(v)
    Dim c As Class1
    Set c = New Class1

    Dim ind As Long
    For ind = LBound(v) To UBound(v)
        Call c.strange("", v(ind))
    Next ind
End Sub

就像这样:

call outer2(array("a","b","c"))

我得到的输出如下:

 101788312 
 101788328 
 101788344 

增量 16 让我怀疑,但我真的不知道。另外,传递一个值,例如通过调用:

Call c.strange("", CStr(v(ind)))

工作得很好。

编辑:更多信息...如果我将“c.strange”的返回值分配给某个东西而不是扔掉它,我会得到相同的行为:

Public Sub outer3(v)
    Dim c As Class1
    Set c = New Class1

    Dim x
    x = c.strange("", v(LBound(v)))

    Call c.not_strange("", v(LBound(v)))
    Call c.also_not_strange(v(LBound(v)))

    Call not_strange_either("", v(LBound(v)))
End Sub

有趣的是,如果我如上所述调用我的测试例程,并带有一个参数由于调用“Array”,假定的指针值发生变化。但是,如果我这样调用:

call outer([{1,2,3}])

即使我重复拨打电话,我也会得到相同的号码。 (如果我切换到 Windows 中的另一个应用程序,例如我的浏览器,该数字会发生变化。)所以,现在我很好奇 Excel 求值器(用括号调用)似乎会缓存其结果......

FINAL EDIT: It does indeed appear to be a compiler bug - see the accepted answer.

Using VBA within Excel 2007, I have the following code in 'Class1':

Option Explicit

Public Function strange(dummy As String, ParamArray pa())
    Debug.Print pa(LBound(pa))
End Function

Public Sub not_strange(dummy As String, ParamArray pa())
    Debug.Print pa(LBound(pa))
End Sub

Public Function also_not_strange(ParamArray pa())
    Debug.Print pa(LBound(pa))
End Function

and some mode code in a module:

Option Explicit

Public Function not_strange_either(dummy As String, ParamArray pa())
    Debug.Print pa(LBound(pa))
End Function

Public Sub outer(v)
    Dim c As Class1
    Set c = New Class1

    Call c.strange("", v(LBound(v)))
    Call c.not_strange("", v(LBound(v)))
    Call c.also_not_strange(v(LBound(v)))

    Call not_strange_either("", v(LBound(v)))
End Sub

If call 'outer' from the Immediate window like this:

call outer(array("a"))

I get back output that seems strange:

 102085832 
a
a
a

It seems to matter whether the called routine is in a class module or not, whether it is a Sub or a Function, and whether or not there is an initial argument. Am I missing something about how VBA is supposed to work? Any ideas?

The strange number changes from run to run. I say "looks suspiciously like a pointer" because if I call this:

Public Sub outer2(v)
    Dim c As Class1
    Set c = New Class1

    Dim ind As Long
    For ind = LBound(v) To UBound(v)
        Call c.strange("", v(ind))
    Next ind
End Sub

like so:

call outer2(array("a","b","c"))

I get back output like:

 101788312 
 101788328 
 101788344 

It's the increment by 16 that makes me suspicious, but I really don't know. Also, passing a value, say by calling:

Call c.strange("", CStr(v(ind)))

works just fine.

EDIT: A little more info...If I assign the return value from 'c.strange' to something instead of throwing it away, I get the same behavior:

Public Sub outer3(v)
    Dim c As Class1
    Set c = New Class1

    Dim x
    x = c.strange("", v(LBound(v)))

    Call c.not_strange("", v(LBound(v)))
    Call c.also_not_strange(v(LBound(v)))

    Call not_strange_either("", v(LBound(v)))
End Sub

Interestingly, if I call my test routines as above, with an argument that results from calling 'Array', the supposed-pointer value changes. However, if I call it like this:

call outer([{1,2,3}])

I get back the same number, even if I make the call repeatedly. (The number changes if I switch to another app in Windows, like my browser.) So, now I'm intrigued that the Excel evaluator (invoked with the brackets) seemingly caches its results...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

倦话 2024-09-19 05:08:47

现在这太棒了。

转载于 Office 2003。
看起来像一个编译器错误。

问题出在这一行:

Call c.strange("", v(LBound(v)))

这里编译器创建一个 Variant ,它保存一个 Variant 的一维数组,其中唯一的元素是指针而不是值。然后,该指针转到奇怪的函数,该函数实际上并不奇怪,它只打印传递给它的 Variant\Long 值。

这个技巧使编译器恢复理智:

Call c.strange("", (v(LBound(v))))

编辑

是的,这个幻数是指向 VARIANT 结构的指针,该结构应该传递给奇怪的方法。第一个字段是8,即vbString,数据字段包含一个指向实际字符串"a"的指针。

因此,这绝对是一个编译器错误...又一个关于数组的 VB 编译器错误;)

Now this is awesome.

Reproduced on office 2003.
Looks like a compiler bug.

The problem is in this line:

Call c.strange("", v(LBound(v)))

Here the compiler creates a Variant that holds a 1D array of Variant's, the only element of which is a pointer instead of the value. This pointer then goes to the strange function which actually is not strange, it only prints the Variant\Long value passed to it.

This trick brings the compiler sanity back:

Call c.strange("", (v(LBound(v))))

EDIT

Yes, this magic number is a pointer to the VARIANT structure which is supposed to be passed to the strange method. The first field of which is 8, which is vbString, and the data field contains a pointer to the actual string "a".

Therefore, it is definitely a compiler bug... Yet another VB compiler bug in regard of arrays ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文