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

AnA*_*ons 5 c arrays c99 language-lawyer

以下是为了在函数原型中添加用于声明数组类型的花哨星形语法的理由而写的* - 只是为了在我们进入问题之前澄清:

函数原型可以使用具有特殊语法的参数具有可变长度数组类型(第6.7.5.2节), int minimum(int,int [*][*]);这与其他不需要指定参数名称的C原型一致.

但我非常有信心,我们可以通过简单地只使用具有未指定大小的普通数组来实现相同的效果(这里重新编写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");
}
Run Code Online (Sandbox Code Playgroud)

因为我很确定标准中有一些地方说明2个阵列只有在它们的大小相等时才兼容,如果它们是可变的则无关紧要.

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

好的除此之外 - 您能指出一个单一的用例,[*]使用普通的未指定大小的数组无法替换吗?

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

对于不了解C的人(或任何认为他/她知道它的人) - 类型数组的函数参数被隐式转换为"指向其元素类型的指针".所以这:

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

调整为:

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

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

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

没有任何后果和与上述2种形式相同的行为.从而使[*]形式过时.

n. *_* m. 6

[]只能用作多维数组中最左边的"维度说明符",而[*]可以在任何地方使用.

在函数参数声明中,最左边(只有!)[...]被调整为(*)无论如何,因此可以(*)在某个清晰度的代价中使用该位置.

可以省略下一个左侧的维度[...],留下空括号.这将使数组元素类型不完整.这不是什么大问题,因为可以在接近使用点(例如在函数定义中)完成它.

下一个[...]需要一个或*不能省略的内部.这些声明

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

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

因此,[*]至少对于尺寸3和以上是必要的.


Grz*_*ski 6

好的除此之外 - 您能指出一个[*]的单个用例,使用普通的未指定大小的数组无法替换吗?

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

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

这可以写成:

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

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

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

但是你没有可能忽略或绕过最后的指示,因此它必须保持[*]在这样的声明中.

  • @CisNOTthatGOODbutISOisTHATBAD,总而言之,您对自己的问题的答案不感兴趣. (2认同)