为什么这个结构24的大小?

man*_*ans 20 c c++ struct sizeof memory-alignment

我有一个结构,我想计算它的大小:

#pragma pack(push,4)
struct  MyStruct
{  
    uint32_t i1;    /* size=4, offset=0. */
    uint32_t i2;    /* size =4 offset =4 */
    uint16_t s1;    /* size =2 offset=8 */
    unsigned char c[8]; /* size=8 offset=12*/
    uint16_t s2;    /* size=2 offset=20. */
    uint16_t s3;    /* size=2 offset=24. */

} ; // total size is 26 

static_assert(sizeof(MyStruct) == 24, "size of MyStruct incorrect");
#pragma pack(pop)
Run Code Online (Sandbox Code Playgroud)

静态断言显示大小为24,但我的计算表明它应该是26.

为什么尺寸为24?

我正在使用visual studio 2012处理Windows 7,32位应用程序

Wal*_*ter 26

对齐uint16_t仅为2,因此偏移量为:

#pragma pack(push,4)
struct  MyStruct
{  
    uint32_t i1;        /* offset=0  size=4 */
    uint32_t i2;        /* offset=4  size=4 */
    uint16_t s1;        /* offset=8  size=2 */
    unsigned char c[8]; /* offset=10 size=8 */
    uint16_t s2;        /* offset=18 size=2 */
    uint16_t s3;        /* offset=20 size=2 */
                        /* offset=22 padding=2 (needed to align MyStruct) */
} ; // total size is 24
Run Code Online (Sandbox Code Playgroud)

编辑 最后的填充是必要的,以确保所有元素

MyStruct A[10]; // or
MyStruct*B = new MyStruct[10];
Run Code Online (Sandbox Code Playgroud)

适当调整.这要求sizeof(MyStruct)是倍数 alignof(MyStruct).这里,sizeof(MyStruct)= 6*alignof(MyStruct).

任何struct/ class类型总是填充到其对齐的下一个倍数.

  • 可能要提一下MS特定的`#pragma pack`的[文档](http://msdn.microsoft.com/en-us/library/2e70t5y1.aspx):"成员的对齐方式将在边界是n的倍数或成员大小的倍数,以**为小**"(强调我的) (17认同)
  • #pragma pack设置最大对齐,因此通常需要超过4个字节对齐的成员将是4字节对齐,需要少于4个字节的成员将获得它们通常的对齐方式. (6认同)

Lun*_*din 22

除了沃尔特的回答,考虑自己捕捉这条鱼.您只需要printf函数和简单的算术:

  struct MyStruct ms;

  printf("sizeof(ms): %zd\n", sizeof(ms));

  printf("i1\t%td\n", (uint8_t*)&ms.i1 - (uint8_t*)&ms);
  printf("i2\t%td\n", (uint8_t*)&ms.i2 - (uint8_t*)&ms);
  printf("s1\t%td\n", (uint8_t*)&ms.s1 - (uint8_t*)&ms);
  printf("c \t%td\n", (uint8_t*)&ms.c  - (uint8_t*)&ms);
  printf("s2\t%td\n", (uint8_t*)&ms.s2 - (uint8_t*)&ms);
  printf("s3\t%td\n", (uint8_t*)&ms.s3 - (uint8_t*)&ms);
Run Code Online (Sandbox Code Playgroud)

(%zd用于打印size_t,%td打印ptrdiff_t.普通%d纸在大多数系统上都可以正常工作.)

输出:

sizeof(ms): 24
i1      0
i2      4
s1      8
c       10
s2      18
s3      20
Run Code Online (Sandbox Code Playgroud)

  • @Lundin:是的,但是大小和偏移量是按字节而不是八位字节来定义的.如果`CHAR_BIT> 8`,则'uint8_t`不存在.当然,指针减法的所有用法都可以用标准的`offsetof`宏代替. (6认同)
  • 使用'size_t`和`ptrdiff_t`的正确格式说明符+1,虽然`%d`绝对不能正常工作(因为签名不匹配).(和'ptrdiff_t`可能是`long`的别名,特别是在64位系统上,所以再次建议不要用'%d`打印它.) (4认同)
  • @KeithThompson出于旧习惯.除了字符串,我从不使用char类型.因为C中的默认原始数据类型是危险的,不可移植的,应该放弃使用stdint.h类型.但也因为在任何类型的算术中使用char是一个非常糟糕的主意,特别是在进行位或字节操作时,因为char的impl.定义签名. (3认同)
  • @KeithThompson offsetof确实比较优雅,因为我使用那个太久了,我忘了它存在:)无论如何,上面的代码表明没有神秘的魔法涉及struct padding:你可以轻松编写代码来找出哪里一切都存储在. (3认同)
  • 为什么不使用`char*`而不是`uint8_t*`? (2认同)