大小为0的数组

42

今天我无意中定义了一个二维数组,其中一个维度的大小为0,但是我的编译器没有抱怨。我找到了以下内容,说明这在gcc中是合法的:

6.17 长度为零的数组

然而,我有两个关于这种用法的问题:

首先,这被认为是良好的编程实践吗?如果是,那么我们应该在什么情况下在真实世界中使用它?

其次,我定义的数组是二维的,其中一个维度的大小为0。这和一维情况下是一样的吗?例如,

int s[0]
int s[0][100]
int s[100][0]
他们在内存中和编译器中都是一样的吗?
编辑:回答Greg:我使用的编译器是gcc 4.4.5。我解决这个问题的意图并不依赖于编译器,但是如果有任何编译器特定的怪癖也会很有帮助 :)
提前致谢!

鉴于您在问题中提到了编译器,提供有关您所关心的特定编译器的信息将会很有帮助。 - Greg
1
请查看此链接:https://dev59.com/tXVC5IYBdhLWcg3wcgmd - vasin
请注意,使用C++11,std::array类型可以具有大小为0(但普通数组仍必须至少有一个元素)。 - Cameron
2
@JimFell,我不否认这些是重复的问题并且另一个问题更受欢迎,但是这个问题出现得早了一年 - 我真的很好奇为什么不是相反的情况呢? - zw324
4个回答

38

在C++中,声明长度为零的数组是不合法的。因此,通常不被认为是好的编程实践,因为这样会将您的代码与特定的编译器扩展绑定在一起。许多使用动态大小数组的情况最好用容器类(例如std::vector)来替代。

ISO/IEC 14882:2003 8.3.4/1:

如果存在常量表达式(5.19),则它应该是一个整数常量表达式,其值应大于零。

但是,您可以使用new[]动态分配长度为零的数组。

ISO/IEC 14882:2003 5.3.4/6:

直接新申明符中的表达式应具有整数或枚举类型(3.9.1),并具有非负值。


1
Charles无法理解您如何动态分配长度为零的数组,您能详细说明一下吗? - Krishna Oza
3
你可以这样做:int *x = new int[0]; 这会返回一个指针,但对其进行解引用是未定义的行为,因为没有任何理由这样做。编译器可能会使对其进行解引用的结果变成任何事情,包括导致程序崩溃。 - smead

4
我在 ideone.com 上运行了这个程序。
#include <iostream>

int main()
{
    int a[0];
    int b[0][100];
    int c[100][0];

    std::cout << "sizeof(a) = " << sizeof(a) << std::endl;
    std::cout << "sizeof(b) = " << sizeof(b) << std::endl;
    std::cout << "sizeof(c) = " << sizeof(c) << std::endl;

    return 0;
}

它将所有变量的大小都设置为0。
sizeof(a) = 0
sizeof(b) = 0
sizeof(c) = 0

在上面的例子中,没有为 abc 分配任何内存。

请在回答中添加它在哪个编译器上执行,因为您指定的链接没有显示代码。 - Krishna Oza
@Krishna_Oza ideone.com在2015年10月20日使用gcc 5.1,这是为数不多支持空数组的编译器之一(我发现这对于通用测试非常方便,可以将不同大小的数组作为参数传递给函数,包括空数组作为有效的测试用例)。 - Dwayne Robinson

2

使用gcc编译您的示例,这三个都具有sizeof 0,因此我会认为编译器会对它们进行相同的处理。


1
这将是编译器的一个错误,而不是供应商扩展。C++要求所有对象的大小至少为1个字节,以便它们可以获得唯一的地址。 - Ben Voigt
这是一个bug。厂商在接受标准未定义行为的代码时有很大的自由裁量权,但当他们这样做时,仍然需要遵循适用的任何标准规则。标准要求每个对象都有唯一的地址和严格正的大小。子对象需要一个与不是父级的每个对象不同的地址。 - Ben Voigt
3
@Ben Voigt:你是正确的,但我仍然会将其定义为扩展而不是错误。我的推理如下:对于数组包含1个或更多元素的每种情况,gcc都按照标准给每个对象分配一个独特的地址。对于零大小的数组,没有创建任何对象,并且不需要分配地址,因此它(在我看来)超出了标准对数组的描述范畴,成为语言的一种有效扩展。换句话说,零大小的数组不是数组,而是其他东西(一种扩展)。 - Kanopus
1
我同意@Kanopus的看法。标准对sizeof有如下阐述。"当应用于数组时,结果是数组中所有字节的总数。这意味着包含n个元素的数组的大小是元素大小的n倍。" 当你选择扩展标准时,通常需要破坏某些东西。 - CB Bailey
VS2010编译器对以零为大小定义的数组抛出错误 error C2466: 无法分配常量大小为0的数组 - Krishna Oza
显示剩余2条评论

2
你的链接解释了一切。它们在结构体中用作最后一个字段,当结构体的长度在编译时未知时使用。如果你尝试将它们用于堆栈或在其他声明的中间,你将会覆盖下一个元素。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接