这个结构怎么能有sizeof == 0?

有一个旧post询问sizeof将返回0的构造。 有一些来自高信誉用户的高分回答说,由标准没有types或variables可以有0的大小,我同意100%。

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

 struct ZeroMemory { int *a[0]; }; 

我正要对它进行倒票和评论,但是在这里度过的时间教会了我去检查我是否100%确定的事情。 所以…令我惊讶的是gccclang显示了相同的结果: sizeof(ZeroMemory) == 0 。 更多的是,一个variables的sizeof是0

 ZeroMemory z{}; static_assert(sizeof(z) == 0); // Awkward... 

Whaaaat …?

Godbolt链接

这怎么可能?

在C被标准化之前,只要代码从未尝试从一个零大小的types中减去一个指针,许多编译器就没有任何困难处理零大小的types。 这种types是有用的,支持他们比禁止他们更容易,更便宜。 其他编译器决定禁止这样的types,然而,一些静态断言代码可能依赖于这样一个事实,即如果代码尝试创build一个零大小的数组,他们会发出警告。 标准的作者面临着一个select:

  1. 即使在这种声明的目的是触发一个诊断和终止编译的情况下,允许编译器默默地接受零大小的数组声明,并要求所有的编译器都接受这样的声明(尽pipe不一定是默默地) 。

  2. 即使在这种声明的目的是触发一个诊断和终止编译,并且允许编译器遇到这种声明的时候,编译器也可以静静地接受零大小的数组声明,或者放弃编译或者在闲暇时继续编译。

  3. 如果代码声明一个零大小的数组,则要求实现发出一个诊断信息,然后允许实现放弃编译或在闲暇时继续它(无论他们认为合适的任何语义)。

该标准的作者select了#3。 因此,标准“扩展”认为零大小的数组声明是可行的,即使这些构造在标准被禁止之前得到了广泛的支持。

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

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

添加-pedantic会产生这个警告:

 5 : <source>:5:12: warning: zero size arrays are an extension [-Wzero-length-array] int *a[0]; ^ 

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

这仍然不能解释行为的sizeof 。 但至less我们知道这不是标准…

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

ISO / IEC 14882:2003 8.3.4 / 1:

如果常数expression式 (5.19)存在, 则它应该是一个积分常数expression式,其值应大于零 。 常量expression式指定数组中的(元素个数)的界限。 如果常量expression式的值为N ,则该数组有N元素,编号为0N-1D的标识符的types是“ N T的派生 – 声明types列表数组”。 [..]

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

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

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