|
回12楼,当你用到的时候,就一点儿不无聊了。
正确答案 sizeof(struct stb)= 24。
为什么?
先讲讲变量的对齐,所谓变量对齐,就是把变量安排在固定的地址边界上,比如1字节地址边界可以是任意地址,2字节地址边界最后一位必须为0,4字节地址边界最后两位必须为0。
在默认的条件,变量都是被对齐到其自然边界的,所谓自然边界,对于基本数据类型来说,就是数据自然长度的地址边界,比如char型是1字节边界,int32型是4字节边界,也就是int32型的变量在默认情况下一定是被放到以0,4,8,c结尾的地址上。基本数据类型的长度在任何情况下(包括使用了pack和align)等于其自然长度或自然长度的整数倍(数组)。
结构体的自然边界等于结构体内部最长字段的自然边界。结构体的长度在默认情况下(不使用align和pack)一定是其自然边界的整数倍,比如一个结构提的自然边界是4,那么结构体的长度(使用sizeof得到的值)必然是4,8,12,16......。
因此,struct sta的自然边界是4字节地址,任何一个struct sta变量的地址都位于以0,4,8,c结尾的地址,struct sta的数据有效长度是sizeof(char)+sizeof(int) = 5,但由于结构体长度必须是自然边界的整数倍,因此sizeof(sta)=8。从另一个角度来看,在struct sta内部,sta.a被放在了起始地址,由前面知道这是一个4字节边界(当然可以做字节边界),后面的sta.b的自然长度是4,必须被放到4字节边界,因此sta.a后面被填充3个字节,整个结构提的长度就是8。
再来看struct stb,其自然边界是8(内部数据最长为long long,8字节),数据有效长度是sizeof(char)+sizeof(struct sta)+sizeof(long long) =17,由于struct stb的长度必须是8的倍数,因此sizeof(stb)=24,从另一个角度看,struct stb必然被安排在以0和8结尾的地址上,所以在struct stb内部,stb.a被放在一个8字节边界地址,后面的stb.b的自然边界是4,必须放到4字节边界地址,因此stb.a后面填充3个字节,接下来紧挨的地址是一个“8字节边界地址+12(stb.a+stb.b的长度)”的地址,这个地址不是8字节边界地址,不能存放stb.c,因此stb.b后面填充4个字节,然后存放stb.c,所以stb的长度是12+4+8=24。
在说一下#pragma pack(n),这个编译器参数是C语言通用的,只对复杂数据类型有效(结构体、类对象),pack(n)规定了结构体内的最大对齐边界为n,当结构体内的字段自然边界小于n时,该字段按照自然边界对齐,否则该字段按照n对齐。同时pack(n)也等于规定了结构体的自然边界为n,使用了pack(n)后,用sizeof求一个结构体的长度,必然是n的整数倍。
另外还有一个伪指令和数据对齐有关,就是align(n)(对于不同的编译器,该伪指令格式不同),align(n)表示把紧随其后的内存安排在n字节的边界地址上,注意align(n)这个指令只是指定起始位置,后面怎么安排取决于处理器当前的对齐设置,同时align(n)也不对结构体内的对齐方式起作用,除非该指令位于结构体内部。比如:
align(4)
char a;
int b;
表示a变量必须放到4字节边界地址,b变量该放哪里放哪里。
如果没有align(4),而是这么写
char a;
int b;
则b变量一定是放在4字节边界地址,而a变量就不一定了,具体放哪里取决于内存排列情况。
align(n)虽然对结构体内部的对齐方式无影响,但放在结构体定义前会影响结构体长度,他规定了结构体的最小自然边界(pack是规定结构体的最大自然边界,同时对内部对齐有影响)。
比如
align(8)
struct sta
{
char a;
short b;
};
此时sizeof(struct sta) = 8,如果没有前面的align(8)则sizeof(struct sta) = 4。但是align不影响结构体内部的对齐方式,不管有无align参数,sta.a总是被放在结构体内部的0地址,sta.b总是被放在结构体内的2字节偏移地址(无pack参数下)。当有align(8)指令时,sta.b后面被填充进4个字节。
总结,align(n)仅仅影响紧随其后的一个变量或数据类型定义,当align(n)放在一个变量定义前时,表示将该变量放入n字节边界地址(如果变量是复杂数据类型,则不影响该变量对应的数据类型的长度),当align(n)放在一个复杂数据类型定义前时,表示指定该复杂数据类型的最小自然边界。pack(n)指定所有数据类型的最大自然边界,全局有效。
所以,记住最关键的一点,使用sizeof得到的结构体长度必然是其自然边界的整数倍,所以7楼回答的20是不对的。
PS:以上皆非转载。 |
|