在函数
中使用变长列表作为参数时int sum(int n, int a[n]);
很容易理解第一个参数(n
)指定第二个参数(a
)的长度。但遇到另一个用于 VLA 的原型作为参数
int sum(int n, int a[*]);
真的很难理解为什么在*
内使用n
代替[]
?
答案 0 :(得分:47)
在声明函数原型时,将使用[*]
语法。这里的关键细节是,在函数原型中,您不需要为参数命名,只需指定每个参数的类型即可。
在您的示例中,如果您保留第一个参数 unnamed ,那么显然您将无法在第二个(数组)参数声明中使用n
。然而,在许多情况下,您必须告诉编译器某些参数是VLA。这是[*]
语法拯救的时候。
在您的情况下,如果省略参数名称,原型可能看起来像
int sum(int, int [*]);
但是,请务必注意,在您的具体示例中,此语法是合法的,但并非完全必要。与非VLA数组一样,int [n]
参数仍然等效于int *
参数(即使对于非常数n
)。这意味着您可以简单地将您的功能原型化为
int sum(int, int []);
或
int sum(int, int *);
并且原型仍将用于其目的,即它将正确匹配函数定义。换句话说,声明为一维数组的参数的VLA属性完全无关紧要,并且这种VLA数组并不真正需要[*]
功能。
[*]
在类型的“变量数组”没有丢失的情况下变得很重要,就像2D VLA(或指向VLA的指针)的情况一样。例如。定义为
int sum2d(int n, int m, int a[n][m])
{
...
}
可能是以下任何
的原型int sum2d(int, int, int a[*][*]);
int sum2d(int n, int, int a[n][*]);
int sum2d(int, int m, int a[*][m]);
int sum2d(int n, int m, int a[n][m]);
以上所有原型都与函数定义完全匹配。
当然,如果您习惯于始终在函数原型中命名所有参数,那么您将永远不需要这种[*]
语法,因为您将能够使用上面列表中的最后一个原型。 / p>
P.S。同样,与参数声明中的所有数组一样,第一个[]
始终是无关紧要的并且总是衰减到指针,这意味着以下也是上述sum2d
的有效等效原型声明
int sum2d(int, int, int a[][*]);
int sum2d(int, int, int (*a)[*]);
int sum2d(int n, int m, int (*a)[m]);
第二个[]
确实很重要,必须声明为“可变长度”。
答案 1 :(得分:4)
当您将星形放入实际函数时,会出现此错误test.c:3: error: ‘[*]’ not allowed in other than function prototype scope
。经过一些研究,这实际上是一种在函数原型中声明VLA的方法,用*
代替变量名。 VLA。
这里的问题是,如果你为VLA添加一个变量而不是星号,它会告诉你它是未声明的,所以这个星是c99内置的方式来绕过它。