user-0 提问: sizeof 一个含结构体的结构体

回复:
user: user-1
content: 如果结构体中的成员又是另外一种结构体类型时，只需把其展开即可。但有一点需要注意，展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大的成员的整数倍。 这里 struct S3 {     char c1;     struct S1 s;     char c2; }; 将其展开 struct S3 {    char c1;    struct S1    {       char  c;       int   i;    }s;    char c2; }; 假如S3.c1 为0x00000000; 则S3.S1.c 为0x00000004;               //注意它的偏移量为4，不是1 S3.S1.i   为0x00000008-0x0000000C; S3.c2     为0x0000000D; 整个S3大小应该是0x00000000-0x000000010;为16

user: user-2
content: 关于这方面的内容确实是依赖于编译器实现的 比如你看下《深入探索C++对象模型》里面对于一个类的实现在g++和微软的编译器的处理就是不一样的 所以这方面内容意义不大 主要还是编译器相关

user: user-3
content: 不要迷信书、考题、老师、回帖； 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实！  有人说一套做一套，你相信他说的还是相信他做的？ 其实严格来说这个世界上古往今来所有人都是说一套做一套，不是吗？  不要写连自己也预测不了结果的代码！

user: user-3
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 // //

user: user-0
content: 不一定是4的倍数，如果pack指定为8，那就是8的倍数了。  引用 7 楼 akirya 的回复:按照起始地址算比较容易。 对于S1 的起始地址只要是4的倍数，就能保证读取c和i都是高效的。  S3中s的地址会保证为4的倍数，那么c1之后就空3字节。 {     char c1;     struct S1 s;     char c2; }; 引用 7 楼 akirya 的回复:按照起始地址算比较容易。 对于S1 的起始地址只要是4的倍数，就能保证读取c和i都是高效的。  S3中s的地址会保证为4的倍数，那么c1之后就空3字节。 {     char c1;     struct S1 s;     char c2; };

user: user-4
content: 按照起始地址算比较容易。 对于S1 的起始地址只要是4的倍数，就能保证读取c和i都是高效的。  S3中s的地址会保证为4的倍数，那么c1之后就空3字节。 {     char c1;     struct S1 s;     char c2; };

user: user-3
content: 理解和讨论之前通常要先学会如何观察和观察什么。

user: user-0
content: 多谢，忘了还有pack这回事。  其实是看了很多，网上查了很多，都是这么说的，结构体里的结构体，如果考虑偏移量是按整体看，如果找最宽的基本类型，是打散了来看。现在想这句话应该是对的，但是同时应该考虑编译器的pack。 就是pack指定为8的时候，看偏移量的时候，那我的s3里的s1不能按4字节处理，要看整体，这个时候就得是8的倍数，如果按4处理就是4的倍数了。  资料上说的对，考虑偏移量时结构体里的结构体看做整体，找结构体里最宽的基本类型时，打散了看。 资料上这句话对，但是很多资料没有把S3为什么是16讲清楚。     引用 1 楼 zhao4zhong1 的回复:#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 // //