为什么对函数的VLA数组参数使用星号"[*]"而不是整数?

hac*_*cks 33 c arrays function function-parameter

在函数中使用变长数组作为参数时

int sum(int n, int a[n]);
Run Code Online (Sandbox Code Playgroud)

很容易理解第一个参数(n)指定第二个参数(a)的长度.但遇到另一个用于VLA的原型作为参数

int sum(int n, int a[*]);
Run Code Online (Sandbox Code Playgroud)

真的很难理解为什么*用而不是在n里面[]

AnT*_*AnT 48

[*]语法旨在声明时要使用函数原型.这里的关键细节是,在函数原型中,您不需要为参数命名,只需指定每个参数的类型即可.

在你的榜样,如果你离开的第一个参数未命名,那么显然,你不能使用n你的第二个(阵列)参数声明.然而,在许多情况下,您必须告诉编译器某些参数是VLA.这是[*]语法拯救的时候.

在您的情况下,如果省略参数名称,原型可能看起来像

int sum(int, int [*]);
Run Code Online (Sandbox Code Playgroud)

但是,请务必注意,在您的特定示例中,此语法是合法的,但并非完全必要.就像非VLA数组一样,int [n]参数仍然等于int *参数(即使对于非常数n).这意味着您可以简单地将您的功能原型化为

int sum(int, int []);
Run Code Online (Sandbox Code Playgroud)

或者作为

int sum(int, int *);
Run Code Online (Sandbox Code Playgroud)

并且原型仍将用于其目的,即它将正确匹配函数定义.换句话说,声明为一维数组的参数的VLA性质是完全无关紧要并且[*]是不是真的需要与这样的VLA阵列特征.

[*]当该类型的"可变arrayness"不丢失,因为将与2D VLA(或一个指向VLA)的情况下变得重要的情况.例如,定义为的函数

int sum2d(int n, int m, int a[n][m])
{
  ...
}
Run Code Online (Sandbox Code Playgroud)

可能是以下任何一个原型

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]);
Run Code Online (Sandbox Code Playgroud)

所有上述原型都与函数定义完全匹配.

当然,如果您习惯于始终在函数原型中命名所有参数,那么您将永远不需要这种[*]语法,因为您将能够使用上面列表中的最后一个原型.

PS再次,与参数声明中的所有数组的情况一样,第一个[]总是无关紧要并且总是衰减到指针,这意味着以下也是上面有效的等效原型声明sum2d

    int sum2d(int, int, int a[][*]);
    int sum2d(int, int, int (*a)[*]);
    int sum2d(int n, int m, int (*a)[m]);
Run Code Online (Sandbox Code Playgroud)

这是[]真正重要的第二个,必须被宣布为"可变长度".

  • 有时您无法轻易地在原型中命名参数.在编写库头时,您希望避免可能与库的用户在预处理器宏中使用的名称冲突的名称.因此,您必须省略名称或步入保留的名称空间(与实现协作)或使库保留名称空间的一部分(与"MyLibrary_"之类的前缀一样).后两者可能变得丑陋. (3认同)
  • @hackks:我指的是数组参数声明中的第一个 `[]` 总是丢失的事实。参数衰减为指针。这适用于所有数组参数声明,无论它们是否为 VLA。(我在答案中说明了这一点)。将“永久非消失数组”“注入”到 C 中的类型的唯一方法是使其成为指向数组的指针,例如 `int (*p)[5]` 或 `int (*p)[n]` . 在参数声明中,这等效于二维数组声明。 (2认同)