我刚刚发现这在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 ++代码?
答案 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)
。