为什么在函数原型中使用“[*]”而不是“[]”?

Why use "[*]" instead of "[]" in function prototype?

这是什么 written 作为添加用于在函数原型中声明数组类型的奇特 * 星号语法的基本原理 - 只是为了在我们进入问题之前澄清一下:

A function prototype can have parameters that have variable length array types (§6.7.5.2) using a special syntax as in int minimum(int,int [*][*]); This is consistent with other C prototypes where the name of the parameter need not be specified.

但我非常有信心,我们可以通过仅使用像这样的未指定大小的普通数组来达到相同的效果(这里重写上面引用中给出的名为 minimum 的函数示例我相信完全相同的功能(除了使用 size_t 而不是 int 作为第一个参数,这在这种情况下并不那么重要):

#include <stdio.h>


int minimum(size_t, int (*)[]);

int (main)()
{
    size_t sz;

    scanf("%zu", &sz);

    int vla[sz];

    for(size_t i = 0; i < sz; ++i)
        vla[i] = i;

    minimum(sizeof(vla) / sizeof(*vla), &vla);

    int a[] = { 5, 4, 3, 2, 1, 0 };

    minimum(sizeof(a) / sizeof(*a), &a);
}


int minimum(size_t a, int (*b)[a])
{  
    for(size_t i = 0; i < sizeof(*b) / sizeof(**b); ++i)
        printf("%d ", (*b)[i]);

    return printf("\n");
}

因为我很确定标准中有一些地方声明只有大小相等的 2 个数组才兼容,无论它们是否可变。

我的观点也得到了以下事实的证实,即 minimum 定义不会抱怨 "conflicting types",因为如果它的某些参数具有不兼容的类型(我认为这不是这种情况因为这两个数组的大小在编译时未指定 - 我指的是 minimum).

的第二个参数

好吧 - 你能给我指出 1 个无法使用普通未指定大小数组替换的 [*] 用例吗?

以上代码使用 clang 和 gcc 编译时没有任何警告。它还会产生预期的输出。

对于任何不了解 C 的人(或任何认为 he/she 了解 C 的人)- 数组类型的函数参数隐式转换为 "pointer to its elements type"。所以这个:

int minimum(int,int [*][*]);

调整为:

int minimum(int,int (*)[*]);

然后我认为它也可以写成:

int minimum(int,int (*)[]);

没有任何后果,并且具有与上述 2 种形式相同的行为。从而使 [*] 形式过时。

[]只能用作多维数组的最左边"dimension specifier",而[*]可以在任何地方使用。

在函数参数声明中,最左边(仅!)的 [...] 无论如何都被调整为 (*),因此可以在该位置使用 (*),但会牺牲一些清晰度。

可以省略最左边 [...] 中的维度,留下空括号。这将使数组元素类型不完整。这没什么大不了的,因为可以在接近使用点的地方完成它(例如在函数定义中)。

下一个[...]需要一个数字或者里面的*不能省略。这些声明

int foo (int [*][*][*]);
int foo (int (*)[*][*]);
int foo (int (*)[ ][*]);

都是兼容的,但没有一个不将第三维指定为 * 或数字的兼容。如果第三维度确实是可变的,那么*是唯一的选择。

因此,至少对于维度 3 及更高维度,[*] 是必需的。

OK besides - can you point me 1 single use-case for [*] that can not be replaced using ordinary unspecified size arrays?

当你传递三维 VLA 数组时,情况就是这样:

int minimum(size_t, int [*][*][*]);

这可以写成:

int minimum(size_t, int (*)[*][*]);

甚至使用未指定大小的数组:

int minimum(size_t, int (*)[][*]);

但是你不可能省略也不会绕过最后一个索引,因此它必须在这样的声明中保持为 [*]