user-0 提问: 关于sizeof(struct)的一点疑问

回复:
user: user-1
content: 注意 系统对齐设置（缺省设置，或者#pragma pack  设置）， 可能会强制较长类型，从非对齐位置开始存放

user: user-1
content: 较短数据类型，跟较长类型放在一起对齐的时候 较短类型会拼接到一起，然后跟较长类型继续拼接 而每种类型的起始位置，都是按照该类型对齐量计算的。

user: user-2
content: 内存对其，默认以pragma pack 中的参数8对齐了。可以使用#pragma pack(4)修改对齐字节。

user: user-3
content: 由于存储变量时地址对齐的要求，编译器在编译程序时会遵循两条原则： 一、结构体变量中成员的偏移量必须是成员大小的整数倍（0被认为是任何数的整数倍）  二、结构体大小必须是所有成员大小的整数倍。

user: user-3
content: 引用 3 楼 yuelengdihai 的回复:8+4+1+1=14,(这个结构体大小必须为8的整数倍，补齐后为16) 没看清题目

user: user-3
content: 8+4+1+1=14,(这个结构体大小必须为8的整数倍，补齐后为16)

user: user-4
content: 引用 楼主 a105112859 的回复:先贴代码 1. struct st1 { 	double df; //8 	int i;           //4 	char c1;    //1 	char c2;    //1 };  -------》 最大的是double类型，自身长度是8，所以是8*2 = 16 2. struct st2 { 	double df; 	char c1; 	int i; 	char c2; };  -------》double占用了8字节，c1和i共用了8个字节，c2用了8字节，所以是24 通过输出，可以看出st1大小为16，st2大小为24,有人知道这是为什么吗？环境是是VS2010 结论：变量定义的位置的不同时有可能影响结构体的大小

user: user-4
content: 字节对齐，本质是以空间换时间。 以GCC为例，字节对齐规则是： 1.结构体内成员按自身长度自对齐。 所谓自对齐，指的是该成员的起始位置的内存地址必须是它自身长度的整数倍。如int只能以0,4,8这类的地址开始 2.结构体的总大小为结构体的有效对齐值的整数倍 结构体的有效对齐值的确定： 1）当未明确指定时，以结构体中最长的成员的长度为其有效值 2）当用#pragma pack(n)指定时，以n和结构体中最长的成员的长度中较小者为其值。 3）当用__attribute__ ((__packed__))指定长度时，强制按照此值为结构体的有效对齐值

user: user-5
content: 不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！   仅供参考： #include <stdio.h> #define field_offset(s,f) (int)(&(((struct s *)(0))->f)) struct AD  { int a; char b[13]; double c;}; #pragma pack(push) #pragma pack(1) struct A1  { int a; char b[13]; double c;}; #pragma pack(2) struct A2  { int a; char b[13]; double c;}; #pragma pack(4) struct A4  { int a; char b[13]; double c;}; #pragma pack(8) struct A8  { int a; char b[13]; double c;}; #pragma pack(16) struct A16 { int a; char b[13]; double c;}; #pragma pack(pop) int main() {     printf("AD.a %d\n",field_offset(AD,a));     printf("AD.b %d\n",field_offset(AD,b));     printf("AD.c %d\n",field_offset(AD,c));     printf("AD sizeof %d\n", sizeof(AD));     printf("\n");     printf("A1.a %d\n",field_offset(A1,a));     printf("A1.b %d\n",field_offset(A1,b));     printf("A1.c %d\n",field_offset(A1,c));     printf("A1 sizeof %d\n", sizeof(A1));     printf("\n");     printf("A2.a %d\n",field_offset(A2,a));     printf("A2.b %d\n",field_offset(A2,b));     printf("A2.c %d\n",field_offset(A2,c));     printf("A2 sizeof %d\n", sizeof(A2));     printf("\n");     printf("A4.a %d\n",field_offset(A4,a));     printf("A4.b %d\n",field_offset(A4,b));     printf("A4.c %d\n",field_offset(A4,c));     printf("A4 sizeof %d\n", sizeof(A4));     printf("\n");     printf("A8.a %d\n",field_offset(A8,a));     printf("A8.b %d\n",field_offset(A8,b));     printf("A8.c %d\n",field_offset(A8,c));     printf("A8 sizeof %d\n", sizeof(A8));     printf("\n");     printf("A16.a %d\n",field_offset(A16,a));     printf("A16.b %d\n",field_offset(A16,b));     printf("A16.c %d\n",field_offset(A16,c));     printf("A16 sizeof %d\n", sizeof(A16));     printf("\n");     return 0; } //AD.a 0 //AD.b 4 //AD.c 24 //AD sizeof 32 // //A1.a 0 //A1.b 4 //A1.c 17 //A1 sizeof 25 // //A2.a 0 //A2.b 4 //A2.c 18 //A2 sizeof 26 // //A4.a 0 //A4.b 4 //A4.c 20 //A4 sizeof 28 // //A8.a 0 //A8.b 4 //A8.c 24 //A8 sizeof 32 // //A16.a 0 //A16.b 4 //A16.c 24 //A16 sizeof 32 // //

user: user-6
content: 要对齐啊，因为int占4个字节，所以推测出地址总线4的字节，假设从地址2开始分配，不对齐，int占据的就是2-5的地址。由于读取是只能是0-3,4-7，4个4个读。可以想到，这样访问这个int需要读两次：先读地址0-3的数据，并抛弃地址0,1上的数据，再读4-7上的数据，抛弃掉地址6,7上的数据，然后组合。如果直接将int存放在3-7的位置上，那直接一次就可以搞定了。 首先VS中默认对齐设置为8 在第一个结构体中，第一个为double，因此min(8,8)等于8,按8字节对齐，占8个字节，                                    第二个为int，min(4,8)=4,而前一个double类型刚好占满了8个，所以紧挨着doube排，占4个字节                                    第三个为char，min(1,8)=1,前面Int再一次占满4个字节，因此它也紧挨着排列，占1                                     第三四个为char，min(1,8)=1,前面char再一次占满1个字节，因此它同样紧挨着排列，占1                                     最后，整个结构体必须长度必须为结构体内最长类型的整数倍，现在只用了8+4+1+1,=14，还不够， 因此，最后还需补两个空 在第二个结构体中，第一个为double，因此min(8,8)等于8,按8字节对齐，占8个字节，                                    第二个为char，min(1,8)=1,而前一个double类型刚好占满了8个，所以紧挨着doube排，占1个字节                                    第三个为int，min(4,8)=4,而前面char仅仅占了1个字节，为了以最少此时访问到，在int之前需要空3个字节，而自己占4个字节                                     第三四个为char，min(1,8)=1,前面int已经占满4个字节，因此它紧挨着排列，占1                                     最后，整个结构体必须长度必须为结构体内最长类型的整数倍，现在只用了8+1+3（空）+4+1,=17，还不够， 因此，最后还需补7个空。 以上本人浅显理解，应该比专业术语好懂。对齐的根本原则就是：使变量能以最少的读取次数访问，

user: user-7
content: 搜索“内存对齐”，还有int可不一定是4字节的，建议用int32_t表示32位有符号整型

user: user-5
content: 仅供参考：#include <stdio.h> #define field_offset(s,f) (int)(&(((struct s *)(0))->f)) struct AD  { int a; char b[13]; double c;}; #pragma pack(push) #pragma pack(1) struct A1  { int a; char b[13]; double c;}; #pragma pack(2) struct A2  { int a; char b[13]; double c;}; #pragma pack(4) struct A4  { int a; char b[13]; double c;}; #pragma pack(8) struct A8  { int a; char b[13]; double c;}; #pragma pack(16) struct A16 { int a; char b[13]; double c;}; #pragma pack(pop) int main() {     printf("AD.a %d\n",field_offset(AD,a));     printf("AD.b %d\n",field_offset(AD,b));     printf("AD.c %d\n",field_offset(AD,c));     printf("\n");     printf("A1.a %d\n",field_offset(A1,a));     printf("A1.b %d\n",field_offset(A1,b));     printf("A1.c %d\n",field_offset(A1,c));     printf("\n");     printf("A2.a %d\n",field_offset(A2,a));     printf("A2.b %d\n",field_offset(A2,b));     printf("A2.c %d\n",field_offset(A2,c));     printf("\n");     printf("A4.a %d\n",field_offset(A4,a));     printf("A4.b %d\n",field_offset(A4,b));     printf("A4.c %d\n",field_offset(A4,c));     printf("\n");     printf("A8.a %d\n",field_offset(A8,a));     printf("A8.b %d\n",field_offset(A8,b));     printf("A8.c %d\n",field_offset(A8,c));     printf("\n");     printf("A16.a %d\n",field_offset(A16,a));     printf("A16.b %d\n",field_offset(A16,b));     printf("A16.c %d\n",field_offset(A16,c));     printf("\n");     return 0; } //AD.a 0 //AD.b 4 //AD.c 24 // //A1.a 0 //A1.b 4 //A1.c 17 // //A2.a 0 //A2.b 4 //A2.c 18 // //A4.a 0 //A4.b 4 //A4.c 20 // //A8.a 0 //A8.b 4 //A8.c 24 // //A16.a 0 //A16.b 4 //A16.c 24 // //