这个结构如何具有sizeof == 0?

bol*_*lov 78 c++ sizeof language-lawyer

有一个旧帖子要求一个sizeof可以返回的构造0.高信誉用户有一些高分答案说,按标准,没有类型或变量可以有0的大小.我同意100%.

然而,这个新的答案提出了这个解决方案:

struct ZeroMemory {
    int *a[0];
};
Run Code Online (Sandbox Code Playgroud)

我正要进行投票和评论,但是在这里度过的时间教会我检查我100%肯定的事情.所以...让我惊讶的是,gccclang显示出相同的结果:sizeof(ZeroMemory) == 0.更重要的是,变量的大小是0:

ZeroMemory z{};
static_assert(sizeof(z) == 0); // Awkward...
Run Code Online (Sandbox Code Playgroud)

Whaaaat ...?

Godbolt链接

这怎么可能?

sup*_*cat 50

在C标准化之前,只要代码从未尝试从另一个指针中减去一个指向零大小类型的指针,许多编译器就可以毫无困难地处理零大小的类型.这些类型很有用,支持它们比禁止它们更容易和更便宜.然而,其他编译器决定禁止这些类型,并且一些静态断言代码可能依赖于如果代码试图创建零大小的数组它们会发出尖叫的事实.标准的作者面临一个选择:

  1. 允许编译器静默接受零大小的数组声明,即使在这种声明的目的是触发诊断和中止编译的情况下,并要求所有编译器接受这样的声明(尽管不一定是静默地)作为生成零大小的对象.

  2. 允许编译器静默接受零大小的数组声明,即使这样的声明的目的是触发诊断和中止编译,并允许编译器遇到这样的声明中止编译或在闲暇时继续它.

  3. 如果代码声明一个零大小的数组,则要求实现发出诊断,但是允许实现中止编译或者在闲暇时继续它(使用他们认为合适的语义).

该标准的作者选择了#3.因此,标准"扩展"认为零大小的数组声明,即使这些结构在标准禁止之前得到广泛支持.

C++标准允许存在空对象,但为了允许空对象的地址可用作标记,它要求它们的最小大小为1.对于没有成员大小为的对象因此0会违反标准.但是,如果一个对象包含零大小的成员,那么除了包含这种声明的程序必须触发诊断这一事实外,C++标准对它的处理方式没有任何要求.由于大多数使用此类声明的代码都希望生成的对象的大小为零,因此接收此类代码的编译器最有用的行为就是以这种方式对待它们.


bol*_*lov 41

正如Jarod42所指出的,零大小的数组不是标准的C++,而是GCC和Clang扩展.

添加-pedantic产生此警告:

5 : <source>:5:12: warning: zero size arrays are an extension [-Wzero-length-array]
    int *a[0];
           ^
Run Code Online (Sandbox Code Playgroud)

我总是忘记std=c++XX(而不是std=gnu++XX)不会禁用所有扩展.

这仍然不能解释这种sizeof行为.但至少我们知道这不标准......

  • 这只能回答零大小的数组是非标准的,但它没有解释你问的问题. (9认同)
  • 有趣的是,如果你创建两个自动实例,它们将存储`sizeof(int*)`(我假设):http://coliru.stacked-crooked.com/a/e9a3038bf587b65c (2认同)

msc*_*msc 18

在C++中,零大小的数组是非法的.

ISO/IEC 14882:2003 8.3.4/1:

[..]如果存在常量表达式(5.19),它应该是一个整数常量表达式,其值应大于零.常量表达式指定数组中的(元素数)的边界.如果常量表达式的值是N,则数组具有N编号0为的元素N-1,并且标识符的类型D是"T的derived-declarator-type-list array N".[..]

g ++要求-pedantic标志在零大小的数组上发出警告.


hac*_*cks 5

零长度数组是 GCC 和 Clang 的扩展。应用于sizeof零长度数组的计算结果为零

C++ 类(空)不能有 size 0,但请注意该类ZeroMemory不为空。它有一个具有大小的命名成员,0应用sizeof将返回零。

  • 所以...空类不能有大小`0`,但非空类可以有大小`0`...这没有多大意义。但我想这是您使用非标准扩展获得的那种相互冲突的边缘情况。 (5认同)
  • @bodov:但这不是 C++ 类,而是 G++ 类,因此 C++ 规则不必适用于它。请特别注意,您不能拥有这种类型的数组或使用其指针进行数学运算,因此通常认为大小不能为零的推理也不成立。 (3认同)