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

时间:2015-01-12 08:10:04

标签: c++ c arrays function pointers

我刚刚发现这在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;
}

使用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));

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

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

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

2 个答案:

答案 0 :(得分:35)

Dan Saks wrote about this in 1995,在C ++标准化之前:

  

委员会决定接受一个这样的功能   指针或对具有未知边界的数组的引用,复杂   C ++中的声明匹配和重载解析规则。该   委员会同意,因为这些功能几乎没有用处   相当不常见,禁止它们是最简单的。因此,   C ++草案现在声明:

     
    

如果参数的类型包含表单指针的类型     T的未知边界数组或对未知边界数组的引用     T,该计划格式不正确。

  

答案 1 :(得分:29)

C ++没有C&#34;兼容类型&#34;的概念。在C中,这是对变量的完全有效的重新声明:

extern int (*a)[];
extern int (*a)[3];

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

extern void f();
extern void f(int);

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

enum E { A, B, C };
extern enum E a;
extern unsigned int a;

C ++没有任何相关内容。在C ++中,类型是相同的,或者是不同的,如果它们不同,那么它们之间的差异就很少了。

类似地,

int main() {
  const char array[] = "Hello";
  const char (*pointer)[] = &array;
}

在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;
}

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