为什么只有在堆分配的情况下才允许零长度数组?

时间:2011-07-28 15:42:31

标签: c++ arrays

我注意到不允许创建零堆长的非堆分配数组。

// error: cannot allocate an array of constant length zero
char a[0];

我还注意到允许创建零长度的堆分配数组。

// this is okay though
char *pa = new char[0];

我猜他们都受到标准的保证(我手边没有标准的副本)。如果是这样,为什么他们如此不同?为什么不在堆栈上允许零长度数组(反之亦然)?

5 个答案:

答案 0 :(得分:16)

这在C ++标准的以下部分中解决。

<强> 3.7.3.1/2:

[32。目的是通过调用new()malloc()来实现运算符calloc(),因此规则基本相同。 C ++与C的不同之处在于要求零请求返回非空指针。]

而且,

5.3.4,第7段

当direct-new-declarator中的表达式的值为零时,调用分配函数来分配没有元素的数组。


C ++标准不允许使用大小为0的数组:

8.3.4 / 1:

“如果_constant-expression+(5.19)存在,它应该是一个整数常量表达式,其值应大于零。”

在我的理解中,这背后的基本原理似乎是C ++标准要求每个对象必须具有唯一的地址(这就是为什么即使空类对象的大小为1也是如此)。在非的情况下堆零大小的数组,不需要创建任何对象,因此不需要给它任何地址,因此不需要首先允许它。


就c而言,零长度数组是 allowed by the c standard ,通常它们用于通过将零长度数组放在结构的末尾来实现具有可变大小的结构。如果我的记忆是正确的,那么它通常被称为 C struct Hack

答案 1 :(得分:6)

0长度数组不是很有用。当你计算的时候 维度,它可以发生,并且不必处理案例是有用的 特别是在你的代码中。在new之外,数组的维度 必须是一个常数,而不是一个计算值,如果你知道的话 常数为0,为什么定义它?

至少,这是我听过的理由(来自那些工作的人) 它)。我并不完全相信:代码中的代码并不罕见 处理其值未知的符号常量(来自标题 文件,甚至命令行)。所以它可能有意义 允许0个元素的数组。并且过去至少有一个编译器 允许他们,虽然我忘记了哪一个。

C ++中的一个常见技巧是在编译时使用这样的数组 断言,如:

char dummyToTestSomeSpecificCondition[ condition ];

如果条件为false,则无法编译,如果是则将编译 事实并非如此。除了那个编译器(如果它仍然存在);我会用的 类似的东西:

char dummyToTestSomeSpecificCondition[ 2 * condition - 1 ];

,以防万一。

答案 2 :(得分:4)

我认为他们表现不同的主要原因是第一个:

char a[0];

是一个大小为0的数组,这是禁止的,因为它的大小应该是定义0 * sizeof(char),而在C或C ++中你不能定义大小为0的类型。

但第二个:

char *pa = new char[0];

不是一个真正的数组,它只是一大块0个 char 类型的对象放在内存中。由于0个对象的序列可能有用,因此允许这样做。它只是将指针返回到最后一个项目,这非常好。

要添加我的论点,请考虑以下示例:

new int[0][3]; //ok: create 0 arrays of 3 integers
new int[3][0]; //error: create 3 arrays of 0 integers

虽然两行都会分配相同的内存(0字节),但一个是允许的,另一个不是。

答案 3 :(得分:1)

这取决于编译器实现/标志。 Visual C ++不允许,GCC允许(不知道如何禁用)。 使用这种方法,STATIC_ASSERT可以在VC中实现,但不能在GCC中实现:

#define STATIC_ASSERT(_cond) { char __dummy[_cond];}

答案 4 :(得分:-1)

即使是直觉上这也是有道理的。

由于堆分配方法在堆栈上创建一个指针,在堆上分配的一块内存中,它仍然“创建一些”大小为sizeof(void*)的东西。在分配零长度数组的情况下,堆栈上存在的指针可以指向任何地方,但无处可见。

相比之下,如果在堆栈上分配数组,那么有意义的零长度数组对象会是什么样子?它没有多大意义。