为什么空数组的类型在结构的内部和外部具有不同的大小?

问题描述

#include <stdio.h>    
struct Obj {
    char a;
    uint32_t b;
    uint8_t c;
    uint64_t d[0];
};
struct Obj1 {
    uint64_t d[0];
};

int main() {
    uint64_t a[0];
    printf("%d\n",sizeof(Obj)); // 16
    printf("%d\n",sizeof(a)); // 16
    printf("%d\n",sizeof(Obj1)); // 16
    //cout << sizeof(Obj) << endl; // 16
    //cout << sizeof(a) << endl;   // 0
    //cout << sizeof(Obj1) << endl; // 0
}

如上所示,为什么结构中的uint64_t变量不会在uint8_t之后立即返回,而且更奇怪的是空数组在结构外部的大小为零。

这实际上是一个面试问题。解释是这样的,尽管仍然无法理解。

如果没有第四个字段,则应为4 + 4 + 4 = 12,加上第四个 字段是16,第四个字段不占用空间,但是它将告诉 编译器对齐8个字节

此用法通常在内核中使用,例如,以下可以 被下标直接访问

Obj o1; uint64_t array[1024]; // In memory,array immediately follows
o1 o1.d[123]; // can access the elements of array

正如评论所指出的,这可能仅适用于C而不是C ++。所以我将代码更改为C版本。

解决方法

首先,您的代码是未定义的行为。来自Arrays p1的重点:

在声明T D中,D的形式为

  D1 [ constant-expressionopt ] attribute-specifier-seqopt 

以及所包含的类型 声明T D1中的declarator-id是“ derived-declarator-type-list” T”,D中声明符的类型为 “ NT的派生声明符类型列表数组”。常量表达式 应该是std :: size_t类型的转换常量表达式 ([expr.const])。 其值N指定数组边界,即 数组中元素的数量; N应大于零。

数组的大小必须大于0。


对于 gcc编译器扩展allows for zero sized arrays在C代码中并且恰好在C ++代码中也受支持,gcc文档指出:

尽管零长度数组的大小为零,但由于尾部填充,这种数组成员可能会增加封闭类型的大小。

您的代码中似乎正在发生这种情况。

,

这个面试问题探究了候选人在C标准和特定实现中的对齐方式和某些语义。

char a成员的大小为1(字节),对齐要求为1(字节)。

uint32_t b成员的大小为4,通常具有四个字节的对齐要求。为了将其放置在四个字节的倍数的地址上,编译器必须在a之后和b之前包括三个未使用的字节,它们正在调用填充字节。到目前为止,该结构需要1 + 3 + 4 = 8个字节。

uint8_t c成员的大小为1,对齐要求为1。到目前为止,该结构需要9个字节。

对于uint64_t d[0],行为不是由C标准定义的。但是,除非访问员指定了这是关于严格符合标准C的问题,否则回答行为未定义是不充分的,因为C不仅限于标准。还存在C(但不是严格符合)的C和非标准的C变体。GCC支持众所周知的扩展,其中结构的最后一个成员可以声明为具有零元素的数组,并且访调员希望提问者要知道这一点。

使用这种结构时,程序必须通过将这样的空间添加到使用malloc或类似的内存分配例程的请求中,为它希望使用的任何数组元素分配足够的空间。例如,要为基本结构和13个元素分配空间,可以使用malloc(sizeof(struct Obj) + 13 * sizeof(uint64_t))

通常,uint64_t的对齐要求为八个字节。无论其对齐要求是什么,编译器都会在成员cd之间添加足够的未使用字节,以确保d具有正确的对齐方式。如果确实需要八字节对齐,则必须在c之后插入七个字节,因此直到d开头的结构大小为1 + 3 + 4 + 1 + 7 = 16字节

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...