sizeof(),C结构中的对齐方式:

Mor*_*ayS 6 c struct alignment

前言: 我对结构对齐的研究.看着这个问题,一个也是这个 - 但仍然没有找到我的答案.

我的实际问题:

这是我创建的代码片段,以澄清我的问题:

#include "stdafx.h"
#include <stdio.h>

struct IntAndCharStruct
{
    int a;
    char b;
};

struct IntAndDoubleStruct
{
    int a;
    double d;
};

struct IntFloatAndDoubleStruct
{
    int a;
    float c;
    double d;
};

int main()
{
    printf("Int: %d\n", sizeof(int));
    printf("Float: %d\n", sizeof(float));
    printf("Char: %d\n", sizeof(char));
    printf("Double: %d\n", sizeof(double));
    printf("IntAndCharStruct: %d\n", sizeof(IntAndCharStruct));
    printf("IntAndDoubleStruct: %d\n", sizeof(IntAndDoubleStruct));
    printf("IntFloatAndDoubleStruct: %d\n", sizeof(IntFloatAndDoubleStruct));
    getchar();
}
Run Code Online (Sandbox Code Playgroud)

它的输出是:

Int: 4
Float: 4
Char: 1
Double: 8
IntAndCharStruct: 8
IntAndDoubleStruct: 16
IntFloatAndDoubleStruct: 16
Run Code Online (Sandbox Code Playgroud)

我得到了在IntAndCharStruct和中的对齐IntAndDoubleStruct.

但我只是不明白的IntFloatAndDoubleStruct一个.

简单地说:为什么不sizeof(IntFloatAndDoubleStruct) = 24呢?

提前致谢!

ps:我正在使用Visual-Studio 2017标准控制台应用程序.

编辑:每个评论,测试IntDoubleAndFloatStruct(不同的元素顺序),并得到24 sizeof()- 如果答案会注意并解释这个案例我会很高兴.

Rei*_*ica 6

在你的平台上,以下成立:的大小intfloat都是4的大小和对齐要求double是8.

我们从sizeof您显示的输出中了解到这一点.sizeof (T)给出T数组中两个连续元素的地址之间的字节数.所以我们知道对齐要求就像我上面所说的那样.(注意)

现在,编译器报告了16 IntFloatAndDoubleStruct.它有用吗?

假设我们在对齐到16的地址处有这样的对象.

  • int a因此在地址X对齐到16,所以它与4对齐就好了.它将占用字节[X,X + 4)
  • 这意味着float c可以从X + 4开始,它与4对齐,这很好float.它将占用字节[X + 4,X + 8)
  • 最后,double d可以从X + 8开始,它与8对齐,这很好double.它将占用字节[X + 8,X + 16)
  • 这为下一个struct对象留下了X + 16空闲,再次与16对齐.

所以以后没有理由启动任何成员,因此整个结构适合16个字节就好了.


(注)这并非严格正确:对于这些中的每一个,我们都知道大小和对齐都是<= N,N是对齐要求的倍数,并且没有N1 <N,这也是.然而,这是一个非常精细的细节,为了清楚起见,答案只是假设基本类型的实际大小和对齐要求是不确定的,这无论如何都是OP平台上最可能的情况.


CIs*_*ies 5

你的结构必须是8*N字节长,因为它有一个8字节(double)的成员.这意味着结构位于存储器中的地址(A)可以被8()整除A%8 == 0,其结束地址将是(A + 8N),它也可以被8整除.

从那里,您存储2个4字节变量(int+ float),这意味着您现在占用了内存区域[A,A+8).现在存储一个8字节的变量(double).自(A+8) % 8 == 0[since A%8 == 0] 以来不需要填充.所以,没有填充,你得到了4+4+8 == 16.

如果改变顺序,int -> double -> float你将占用24个字节,因为double变量原始地址不能被8整除,并且必须填充4个字节才能获得有效地址(并且结构在结尾处也会有填充).


|--------||--------||--------||--------||--------||--------||--------||--------|
|   each ||   cell ||  here  ||represen||-ts  4  || bytes  ||        ||        |
|--------||--------||--------||--------||--------||--------||--------||--------|

A        A+4       A+8      A+12      A+16      A+20      A+24                      [addresses]
|--------||--------||--------||--------||--------||--------||--------||--------|    
|   int  ||  float || double || double ||        ||        ||        ||        |    [content - basic case]
|--------||--------||--------||--------||--------||--------||--------||--------|

first padding to ensure the double sits on address that is divisble by 8
last  padding to ensure the struct size is divisble by the largest member's size (8)
|--------||--------||--------||--------||--------||--------||--------||--------|    
|   int  || padding|| double || double || float  || padding||        ||        |    [content - change order case]
|--------||--------||--------||--------||--------||--------||--------||--------|
Run Code Online (Sandbox Code Playgroud)