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

Pointer to array of unspecified size "(*p)[]" illegal in C++ but legal in C

本文关键字:非法 但在 语言 未指定 数组 指针 C++      更新时间:2023-10-16

我刚刚发现这在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("%dn", 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("%dn", accumulate(ARRAY_LENGTH(a), &a));

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

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

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

Dan Saks 在 1995 年C++标准化之前写过这篇文章:

委员会决定,诸如此类的职能,接受 指向具有未知边界的数组的指针或引用,使数组复杂化 C++中的声明匹配和重载解析规则。这 各委员会一致认为,由于这些职能用处不大,因此 相当罕见,最简单的方法是禁止它们。因此, C++草案现在规定:

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

C++没有

C的"兼容类型"概念。在 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).

相关文章: