指向未指定大小的数组"(*p)[]"在C++中是非法的,但在C中是合法的

wef*_*fa3 33 c c++ arrays pointers function

我刚刚发现这在C++中是非法的(但在C语言中是合法的):

#include <stdio.h>
#include <stdlib.h>
#define ARRAY_LENGTH(A) (sizeof(A) / sizeof(A[0]))

int accumulate(int n, const int (*array)[])
{
    int i;
    int sum = 0;
    for (i = 0; i < n; ++i) {
        sum += (*array)[i];
    }
    return sum;
}

int main(void)
{
    int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35};
    printf("%d\n", accumulate(ARRAY_LENGTH(a), &a));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它编译没有问题使用gcc -std=c89 -pedantic但无法编译使用g++.当我尝试使用它来编译它时,g++我收到以下错误消息:

main.cpp:5:37: error: parameter 'array' includes pointer to array of unknown bound 'int []'
 int accumulate(int n, int (*array)[])
                                     ^
main.cpp: In function 'int main()':
main.cpp:18:50: error: cannot convert 'int (*)[9]' to 'int (*)[]' for argument '2' to 'int accumulate(int, int (*)[])'
     printf("%d\n", accumulate(ARRAY_LENGTH(a), &a));
Run Code Online (Sandbox Code Playgroud)

我一直在我的C​​代码中使用它很长一段时间,我不知道它在C++中是非法的.对我来说,这似乎是一种有用的方法来记录函数采用一个大小未知的数组.

我想知道为什么这是合法的C但是无效的C++.我也想知道是什么让C++委员会决定把它拿走(并打破与C的兼容性).

那么为什么这个合法的C代码是非法的C++代码呢?

use*_*908 35

Dan Saks在1995年的 C++标准化过程中写到了这一点:

委员会决定接受指针或对具有未知界限的数组的引用这样的函数使C++中的声明匹配和重载解析规则复杂化.委员会同意,由于这些功能几乎没有用处并且相当罕见,因此最简单的禁止它们.因此,C++草案现在声明:

如果参数的类型包括指向T未知边界数组的表单指针类型或对未知边界T的数组的引用,则程序格式错误.

  • [上一届委员会会议通过的] [CWG第393号决议](http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#393)取消了该禁令. (7认同)

小智 29

C++没有C的"兼容类型"概念.在C中,这是对变量的完全有效的重新声明:

extern int (*a)[];
extern int (*a)[3];
Run Code Online (Sandbox Code Playgroud)

在C中,这是对同一函数的完全有效的重新声明:

extern void f();
extern void f(int);
Run Code Online (Sandbox Code Playgroud)

在C中,这是特定于实现的,但通常是对同一变量的有效重新声明:

enum E { A, B, C };
extern enum E a;
extern unsigned int a;
Run Code Online (Sandbox Code Playgroud)

C++没有这些.在C++中,类型可以是相同的,也可以是不同的,如果它们不同,那么它们之间的差异就很少了.

同样的,

int main() {
  const char array[] = "Hello";
  const char (*pointer)[] = &array;
}
Run Code Online (Sandbox Code Playgroud)

在C中有效,但在C++中无效:array尽管[]被声明为长度为6的数组,它pointer被声明为指向未指定长度数组的指针,这是一种不同的类型.没有来自隐式转换const char (*)[6]const char (*)[].

因此,指向未指定长度数组的函数在C++中几乎没用,而且几乎肯定是程序员的一个错误.如果从一个具体的数组实例开始,你几乎总是有这个大小,所以你不能将它的地址传递给你的函数,因为你的类型不匹配.

并且在您的示例中也不需要指向未指定长度的数组:在C中编写它的正常方法(在C++中也恰好有效)是

int accumulate(int n, int *array)
{
    int i;
    int sum = 0;
    for (i = 0; i < n; ++i) {
        sum += array[i];
    }
    return sum;
}
Run Code Online (Sandbox Code Playgroud)

被称为accumulate(ARRAY_LENGTH(a), a).

  • @TC啊,很高兴知道.我想如果它确实被允许,它可能只允许在一个方向.从`char(*)[6]`到`char(*)[]`的隐式转换是安全的,但从`char(*)[]`到`char(*)[6]`的隐式转换不是.因为在C中,甚至没有任何转换(类型只是兼容),你可以编写像`int main(){int array [6]; int(*ptr1)[] =&array; int(*ptr2)[100] = ptr1; 通常甚至没有得到任何编译器警告,更不用说错误了. (2认同)