具有union和位域的结构的大小

pyt*_*hon 3 c struct sizeof memory-alignment bit-fields

我正在尝试计算这个结构的字节大小,并有几个问题

struct stc {
    int a;
    int b;
    char c;
    union stc2 {
        long a0;
        int a1;
        int a2;
    };
    char arr[10];
    int z:2;
};
Run Code Online (Sandbox Code Playgroud)

我正在用这种方式检查大小:

int main(void) {
    printf("%zu\n", sizeof(struct stc));
}
Run Code Online (Sandbox Code Playgroud)

并编译:

gcc -std=c99 -m32 -Wall -Wextra test.c

这是gcc 4.9,我在64位计算机上,但首先要尝试32位值,所以-m32.现在,结果是20,但我不知道为什么会这样.这就是我的计算方式.

struct stc {     
    int a;        // +4 = 4
    int b;        // +4 = 8
    char c;       // +1 but next is long, so +4 (alignment) = 12
    union stc2 {
        long a0;  // +4 = 16
        int a1;
        int a2;
    };
    char arr[10]; // +8 (for arr[8]) and 2 bits left = 24 (or 28)
    int z:2;      // +4 = 28 (or 32) 
                  // I'm not sure how it'll work with 2 bits left from char array and
                  // 2 bits from int, so that why I count 2 different values. 
};
Run Code Online (Sandbox Code Playgroud)

这很奇怪所以我试图解决这个问题,我知道这个联盟似乎是0号.

struct stc {
    union stc2 {
        long a0;
        int a1;
        int a2;
    };
Run Code Online (Sandbox Code Playgroud)

sizeof(struct stc) == 0.我认为这是因为编译器优化?如果是这样,如何将其关闭?如果没有,为什么?另一个问题当然是如何正确计算这个结构的大小(有或没有优化)以及为什么这个简单结构的大小:

struct stc {
    char arr[10];
};
Run Code Online (Sandbox Code Playgroud)

是10而不是12.我认为如果你不说编译器没有对齐值,那么每个值都与4,8,12,16,20等对齐.

Bil*_*nch 5

所以你在这里有很多问题.我去的时候会回答一些问题:

sizeof结构是零?

你给了代码:

struct stc {
    union stc2 {
        long a0;
        int a1;
        int a2;
    };
};
Run Code Online (Sandbox Code Playgroud)

请注意,您在结构中声明了没有变量.您可能打算执行以下操作,其大小可能与之相同sizeof(long).

struct stc {
    union stc2 {
        long a0;
        int a1;
        int a2;
    } x;
};
Run Code Online (Sandbox Code Playgroud)

位域布局

所以,让我们试着找出来自哪里20.首先,让我们重新选择类型而不union做任何事情(见前一个标题).

另请注意,具有位域的结构不需要以与普通类型相同的方式布局在内存中.但是,无论如何我们都要做出一些猜测.

struct stc {
    int a;        // Offset 0,  Size 4
    int b;        // Offset 4,  Size 4
    char c;       // Offset 8,  Size 1
    char arr[10]; // Offset 9,  Size 10
    int z:2;      // Offset 19, Size 1-ish
};
Run Code Online (Sandbox Code Playgroud)

所以看起来很合适.

sizeof没有四舍五入到12?

struct stc {
    char arr[10];
};
Run Code Online (Sandbox Code Playgroud)

因此,每种类型都有一个大小和对齐要求.因为char,这两者都是1.因为uint32_t它们通常都是4.但是根据架构,对齐可能不同.

所以在这种情况下,结构的任何元素的最大对齐需求stc是1.因此整个结构的对齐要求仍然是1,即使大小是10.

一般来说,您希望添加大小所需的填充,以便声明struct stc x[2]将导致所有元素正确对齐.

建议

因此,您可以在此处执行一些操作来帮助了解编译器正在执行的操作.

  1. 在堆栈溢出时发布有关内存布局的问题时,使用中定义的类型非常有用stdint.h.这些包括类似int32_tint16_t.这些更好,因为对于什么尺寸没有混淆long.

  2. 您可以使用offsetof工具来确定编译器放置成员的位置.您可以在此处了解有关如何使用它的更多信息.

填充可能会发生:

这是一个非常简单的结构示例,它具有编译器必须插入的大量填充.

struct x {
    uint64_t x; // Offset 0,  Size 8
    char     y; // Offset 8,  Size 1
                // Offset 9,  Size 1 (Padding)
    uint16_t z; // Offset 10, Size 2
                // Offset 12, Size 4 (Padding)
}; 
Run Code Online (Sandbox Code Playgroud)