C语言中结构体的大小

64

可能是重复问题:
为什么结构体的sizeof不等于每个成员的sizeof之和?

考虑以下C代码:

#include <stdio.h>    

struct employee
{
  int id;
  char name[30];  
};

int main()
{
  struct employee e1;      
  printf("%d %d %d", sizeof(e1.id), sizeof(e1.name), sizeof(e1));
  return(0);
}

输出结果为:

4 30 36

为什么结构体的大小不等于其各个组成变量大小的总和?


3
你可以在gcc中使用属性“packed”来去除填充(padding),使结构尽可能地小。结构体test_t的定义如下: struct test_t { int c; } attribute((packed)); - eaanon01
至少是 https://dev59.com/jnVD5IYBdhLWcg3wAWoO 的副本 - dmckee --- ex-moderator kitten
10
eaanon01。除非有非常好的理由并且所有影响都被理解,否则您不应该告诉任何人关于像属性打包这样不可移植的东西。 - Peeter Joot
参见:http://stackoverflow.com/questions/833526/why-short-is-stored-as-4-bytes-in-a-struct-in-c 和 https://dev59.com/fXVC5IYBdhLWcg3w7V33 - dmckee --- ex-moderator kitten
1
请参考这篇关于内存对齐的 C FAQ:http://c-faq.com/struct/align.esr.html。 - Richard Chambers
4个回答

82
编译器可能添加填充以满足对齐要求。注意,这不仅适用于结构体字段之间的填充,还可能适用于结构体末尾(使得结构体类型的数组中每个元素都得到正确对齐)。
例如:
struct foo_t {
    int x;
    char c;
};

尽管c字段不需要填充,但在32位系统(或具有32位int类型的系统)上,结构体通常会具有sizeof(struct foo_t)== 8,因为在c字段之后需要3个字节的填充。

请注意,尽管某些系统(如x86或Cortex M3)可能不需要填充,但编译器出于性能原因可能仍会添加填充。


1
+1,虽然对齐到6个字节听起来有点奇怪。也许我在低级别的东西上有些落后了。 - Michael Krelin - hacker
2
嗯,名称从偏移量4开始(很合理),一直延伸到34。34不是4的倍数,所以在末尾填充到36,即9乘以4。对我来说很有道理! - Carl Smotricz
3
它正在对齐到32位边界(4、8、16、24、32、36...)。 - Mordachai
9
它没有对齐到6个字节。int占用4个字节,char[30]占用32个字节,两者都是4的倍数,使得结构体的大小也是4的倍数。 - Sinan Ünür
尽管我知道回答比搜索重复内容更快,但你必须意识到这个问题以前已经被问及并得到了解答。 - dmckee --- ex-moderator kitten
显示剩余4条评论

3

将内存对齐到6个字节并不奇怪,因为它是对齐到地址的倍数4。

所以基本上你的结构体有34个字节,下一个结构体应该放置在地址上,它是4的倍数。在34之后最接近的值是36。这个填充区域也计入结构体的大小。


3
正如提到的那样,C编译器会为了对齐要求而添加填充。这些要求通常与内存子系统有关。某些类型的计算机只能访问对齐到某个“好”的值的内存,例如4字节。这通常与字长相同。因此,C编译器可能会将结构中的字段对齐到该值,以便更容易访问它们(例如,4字节值应对齐为4字节)。此外,它可能会填充结构底部以对齐跟随结构的数据。我相信还有其他原因。更多信息可以在维基百科页面找到。

3

您的默认对齐方式可能是4个字节。30字节的元素可能会变成32字节,或者整个结构体会向上舍入到下一个4字节间隔。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接