为啥通过 ParamArray 将数组元素传递给函数时,varpointer 会到达函数中?

Posted

技术标签:

【中文标题】为啥通过 ParamArray 将数组元素传递给函数时,varpointer 会到达函数中?【英文标题】:Why, when passing an array element to a function through a ParamArray, does a varpointer arrive in the function?为什么通过 ParamArray 将数组元素传递给函数时,varpointer 会到达函数中? 【发布时间】:2019-02-09 12:24:58 【问题描述】:

在使用ParamArray 并通过它传递数组元素时,我注意到VBA 中有一个奇怪的地方。在某些情况下,到达函数的不是数组元素的值,而是 var 指针。 (Excel 2016,32 位)。

经过一番折腾后,我发现将函数定义为变体数组 - 结合参数列表和 ParamArray - 似乎是意外行为的起源,但我看不出任何可行的原因为什么会这样。

在以下情况下行为恢复正常: 1) 变量 r 在函数声明中被删除 2) b 声明为 Dim b() 3) 函数返回Variant,而不是Variant()

我很欣赏这是一个相当深奥的问题,而且它似乎可以通过各种方式进行控制,但是否有解释这种行为的解释?

Sub Variantarraybug()
   Dim b: b = [1, 2, 3]

   Debug.Print farray1(2, b(1))(0)
   Debug.Print Application.WorksheetFunction.Sum(farray1(2, b(1)))
   Debug.Print Join(farray1(2, b(1)), " ")

   Debug.Print farray2(2, b(1))(0)
   Debug.Print Application.WorksheetFunction.Sum(farray2(2, b(1)))
   Debug.Print Join(farray2(2, b(1)), " ")
   Debug.Print  VarPtr(b(1)), VarPtr(b(2))
End Sub

Function farray1(r, ParamArray plop()) As Variant
   farray1 = Array(plop(0), 3)
End Function
Function farray2(r, ParamArray plop()) As Variant()
   farray2 = Array(plop(0), 5)
End Function

调试窗口中的结果:

 1  
 4  
1 3  
 1  
 6  
358808368 5  
 358808368     358808384 

注1:我的理解是VarPtr函数返回的是那个变量所需内存的起始地址的内存位置。这里仅用于证明farray2 函数看到的意外数字(358808368)实际上是该元素的地址。

注意 2: 这与您如何生成数组(例如 b=array(1,2,3)b=[1,2,3] 等)以及如何声明 bbb(1 to 3))无关, 等等。)。但是,如果您用Dim b() 声明b,意外行为就会消失。 (在这种情况下您不能打印VarPtr(b),因为VarPtr 不能接受数组变量。)

【问题讨论】:

不是真正的解释,但 x = farray2(2, b(1)) Debug.Print Join(x, " ") 将给出字符串中的值而不是指针。看起来 Join 函数在带有 ParamArray 的 Variant() 上的行为不同(不同的评估步骤......??) 你并不孤单!看到这个:***.com/questions/3375562/… 如果您想深入挖掘,我建议采取两种可能的行动方案:1. 您可以使用我的答案here 中的类型来处理底层数据结构 VARIANT 和 SAFEARRAY 2. 您可以反编译实际运行的已编译 VBA 代码,以查看各个 pcode 指令是否显示编译器错误,使用类似this 感谢 Blackhawk,对问题 3375562 的公认答案是它是一个错误。上一个问题确实是相似的,但在实现上有所不同。共同点是函数参数中的第一个元素(上面的 farray 中的 r )对于修改参数数组行为至关重要,并且两个问题都注意到这种行为是不稳定的,并且取决于应该不连接的内容(例如 sub 代替功能,b 的不同声明等) 我认为它是***.com/q/3375562/11683的副本。 【参考方案1】:

我认为这个错误是由于数组“声明”而出现的。 在这一点上,我认为微软明确表示:

数组

您可以声明一个变量来保存一个数组,该数组可以保存多个值。要指定一个变量包含一个数组,请在其变量名后面紧跟括号。

开启here

【讨论】:

我认为你错过了重点:使用 ParamArray 时,有时传递的指针被解释为 'val' 而不是 'var'。【参考方案2】:

我认为,这是“C”中的粗心大意。您会遇到这样的错误

#include <stdio.h>

int main(int argc, char **argv)

   int *X;
   int i;
   
   i = 7;
   X = &i;
   
   printf("%d\n", X);
   printf("%d\n", *X);
   
   return(0);

阐述:

“C”是一种抽象汇编器。您必须了解通过地址(或指针)访问内存的概念。与

int i;

你声明一个变量,它保存一个整数(这个整数的位数取决于编译器)。与

i = 7;

你在内存中定义这个变量的值(这里是 7)。与

int *X;

您声明一个变量,该变量将指针的值(指针的位数取决于编译器;通常整数和指针的位数相等)到包含整数的位置.与

X = &i;

您将指针 X 的值定义为变量 i 的地址。与

*X

您可以访问内存中 X 指向的位置的(整数)值。与

printf("%d\n", X);

您打印指针 X 的值(解释为整数)。与

printf("%d\n", *X);

您打印内存的(整数)值,X 指向的位置。

我相信,有人忘记了“*”。

【讨论】:

你能详细说明一下吗?我不做C.... 希望对您有所帮助...

以上是关于为啥通过 ParamArray 将数组元素传递给函数时,varpointer 会到达函数中?的主要内容,如果未能解决你的问题,请参考以下文章

为啥通过引用传递数组元素会显式导致 IL 中的赋值操作?

forEach 以及 IE兼容

预编译封装

为啥我们不能通过值传递数组来函数?

上传图片函数

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?