函数参数声明中const指针和const数组类型的区别

Difference between const pointer and const array type in function parameter declaration

如果我尝试编译这个小例子:

void f(const int *a) {
    int * ptr = a;
    *ptr = 1;
}

void g(const int a[]) {
    int * ptr = a;
    *ptr = 1;
}

我收到函数 f 的警告和函数 g 的错误。我尝试使用 gcc 9.3.0 和 clang 10.0.0 并得到非常相似的消息。这是来自 gcc 的:

main.c: In function ‘f’:
main.c:4:16: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
    4 |     int* ptr = a;
      |                ^
main.c: In function ‘g’:
main.c:10:5: error: invalid operands to binary * (have ‘const int *’ and ‘int *’)
   10 |     *ptr = 1;
      |     ^

我知道数组和指针有区别,但我一直认为函数参数声明没有区别。在赋值中使用数组和指针作为左手操作数不是完全等价的吗?毕竟我也认为以下是可以互换的:

int main(int argc, char * argv[])

int main(int argc, char ** argv)

我的问题:

编辑 正如 Paul Hankin 指出的那样,我在原始代码中漏掉了一个分号。如果添加,两个函数确实会给出相同的警告消息,这没关系,因为隐式指针转换(如 ptr = a discard const qualifiers.

我在 gcc 和 clang 中得到的两个函数的消息完全相同。您的代码中有一些拼写错误,您在此处发布时没有填写 copy/paste。

I always believed there is no difference in function parameter declaration.

这适用于普通一维数组。诸如 const int a[] 之类的数组参数将被调整(“衰减”)为指向其第一个元素的指针。它 100% 等同于 const int* a。注意 const qualifier 属于 pointed-at 类型,而不是指针本身。

现在碰巧,如果不是这个数组调整规则1),不完整的类型如没有大小的数组实际上不能用作函数参数。这就是为什么你甚至可以在没有大小的情况下键入不完整的数组类型 [] 作为函数参数的原因,因为类型在数组大小重要之前得到调整并且结果不是不完整的类型而是指针(到一个完整的类型)。

然而,这种等价性不能很好地扩展到二维数组。数组参数如 const int a[x][y] 是数组的数组。第一项是数组类型const int[y]。所以它被调整为指向这种类型的指针:
const (*int)[y]。这 兼容 const int* 也不兼容 const int**


1) C17 6.7.6.3

After adjustment, the parameters in a parameter type list in a function declarator that is part of a definition of that function shall not have incomplete type.