为何C++中继承会使含零大小数组的结构体内存膨胀?
空结构体、零长数组相关的sizeof规则与继承行为解析
结合GCC 5.3.0环境下的测试结果,几个核心疑问的逻辑可以从C++标准强制要求、编译器扩展实现规则两个层面拆解:
核心规则拆解
普通空结构体的大小为什么是1字节
C++ ISO标准中有强制约束:除位域外,任何最派生的类实例,大小必须非零,至少占用1字节的存储空间。
- 这条规则的核心目的是保证两个独立声明的对象拥有互不重复的内存地址,避免因为大小为0导致相邻对象地址完全重叠,破坏指针的唯一性语义。
- 对于测试中的
struct a这类没有任何非静态数据成员、无虚函数/虚基类的空结构体,编译器会添加1字节的无名占位,这个占位没有实际存储用途,仅仅是为了满足标准的非零大小要求。因此sizeof(a)的输出固定为1。
含零长数组的结构体大小为什么是0字节
这里首先要明确:零长数组(比如int x[0];的写法)不是标准C++支持的合法语法,这是GCC从C99柔性数组成员特性延伸出的非标准扩展,用于在结构体末尾实现可变长度的动态数组存储。
- GCC对零长数组的存储处理规则是:零长数组本身不占用结构体的固定存储空间,仅作为结构体末尾动态内存区域的标记,计算结构体大小时会直接忽略这类成员的长度。
- 当结构体中没有其他非空的固定大小成员、非零大小的基类,也没有虚函数/虚基类时,排除零长数组后结构体的总大小为0,GCC不会强制套用“最派生对象非零大小”的标准规则给这类扩展类型加1字节占位。因此测试中的
struct b,排除不占空间的x[0]后总大小为0,sizeof(b)输出0。
继承后结构体大小的变化逻辑
测试中的两个继承类表现完全不同,核心原因是基类本身的类型属性不同:
从普通空结构体
a继承的struct c,大小为4字节- 基类
a是符合标准定义的空类,本身触发了“最派生对象必须非零大小”的规则,至少需要1字节的基础占位。 - 类内的
int x[0]虽然不占固定存储空间,但会给整个结构体引入int类型的对齐要求(x86平台上为4字节对齐)。 - 结构体的最终大小必须是自身对齐值的整数倍:原本的1字节占位无法满足4字节的对齐要求,需要补充3字节的填充,最终计算得到的大小为4字节。
补充:虽然GCC默认开启空基类优化(EBO,即空基类子对象不单独占用存储空间,可与其他成员的地址重叠),但这个优化无法绕过“最派生对象非零大小、满足对齐要求”的强制标准规则。
- 基类
从零长数组结构体
b继承的struct d,大小为0字节- 基类
b是GCC扩展定义的0大小类型,本身没有强制的1字节占位要求。 struct d内的int x[0]同样是不占固定空间的零长数组成员,整个类没有任何需要固定存储的非空成员。- GCC在处理这类完全由扩展定义的0大小基类、零长数组成员构成的派生类时,不会套用标准的“非零大小”强制规则,也不会为了满足对齐要求补充填充字节,因此
sizeof(d)的输出为0。
- 基类
内容的提问来源于stack exchange,提问作者Tyler Stoney
相关产品推荐
相关产品推荐

