指向未指定大小的数组的指针在C++"(*p)[]"非法,但在 C 语言中是合法的
Pointer to array of unspecified size "(*p)[]" illegal in C++ but legal in C
我刚刚发现这在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 中,这是对变量的完全有效的重新声明:
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)
.
- 代码在main()中运行,但在函数中出现错误
- 链接阶段在Ubuntu上失败,但在MacOS上失败
- 对C宏的未定义引用,但在定义它时会出现重新定义错误
- c++17文件系统::recursive_directory迭代器()在mac上没有给出这样的目录,但在windows上
- 断言中的Fold表达式在某些计算机上编译,但在其他计算机上不编译
- 换位表导致测试失败(但在游戏中运行良好)
- 库标题在标题中不可见,但在 cmake build 下.cpp文件中完全可见.为什么?
- 树莓上的 Libtorch 无法加载 pt 文件,但在 ubuntu 上工作
- 在成员dynamic_bitset上使用 boost::from_block_range 时出错,但在本地dynamic
- 编译在我的 Mac 上工作,但在集群 (Linux) 上不起作用
- 我编写了代码将十进制分数转换为其二进制等效数.它编译得很好,但在执行时挂起
- 我的代码运行良好,但在游戏循环中中断
- C++ assigment std::list:<typename>:itrator 在 main 中工作,但在方法中它不起作用
- C++代码在台式机上工作正常,但在笔记本电脑上则不行
- 实现 DFS 在较短的输入下工作正常,但在较大的输入下会抛出分段错误
- 点云库在VS 2019中不起作用,但在VS 2017中确实有效
- C++ Python 模块在 Blender 中崩溃,但在 Python 控制台中不会崩溃
- 分段 Linux Ubuntu 中的 g++ 错误,但在 Windows 中的 g++/MingW 中,在 C++ 中打
- 为什么数组大小信息可用于"sizeof"运算符和 delete[] 运算符,但在将数组作为参数传递到
- 指向未指定大小的数组的指针在C++"(*p)[]"非法,但在 C 语言中是合法的