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

时间:2016-06-06 13:11:17

标签: c arrays language-lawyer c99

以下是written作为在函数原型中添加用于声明数组类型的花哨的*星形语法的基本原理 - 仅用于在我们进入问题之前澄清:

  

函数原型可以具有可变长度的参数   数组类型(第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");
}

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

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

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

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

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

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

调整为:

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

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

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

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

2 个答案:

答案 0 :(得分:6)

[]只能用作最左边的&#34;维度说明符&#34;多维数组,而[*]可以在任何地方使用。

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

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

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

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

都是兼容的,但没有一个与它们兼容,并没有将第三个维度指定为*或数字。如果第三维确实是变量,*是唯一的选择。

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

答案 1 :(得分:6)

  

除此之外 - 你能指出一个不能用于[*]的单个用例吗?   使用普通的未指定大小的数组替换?

当您传递三维VLA数组时会出现这种情况:

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

这可以写成:

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

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

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

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