结构体大小的问题虽然简单,但是如果你不仔细的弄清楚,就会经常给你带来麻烦,像我就把昨天的笔试搞砸了,就有这个题目.
今天,为了把这个问题好好弄清楚,在网上疯狂的找了下,终于弄清了结构体怎么算了. 其中有一贴子的回复的确是讲到了点子上,她是这样回答的:
小姑娘找本经典的语言书看看,比如 c和指针,primer 系列的书
结构对齐的默认长度应该是由编译器而定吧,一般是为了方便读取效率和读取的正确性。gcc 默认是 4,vc 默认是 8(这个便是下面说的指定对齐值)。
成员的对齐有自身对齐值、指定对齐值,它们中较小的为有效对齐值。一个结构里的成员的起始地址相对于结构的起始地址的偏移必须是这个有效对齐值的整数倍。
而结构的对齐也有自身对齐值(其成员的自身对齐值中的最大者)、指定对齐值,它们中较小的为结构的有效对齐值。整个结构占用的大小也必须是这个有效对齐值的整数倍。
看了上面的这段话,再来看一个例子吧:
分析:
一、结构体对齐参数按照默认的8字节对齐(指定对齐值),VC默认方式
A和B不讲,在此只分析C和D.
struct C
{
short num; /*在这里,我们按照上面那段话先算这个成员的有效对齐值,可以知道是这个成员自身对齐值(本身的字节数)为2,指定对齐值为8,所以这个成员的有效对齐值(自身与指定对齐值的最小值)为2,偏移地址为2的整数倍,他是第一个成员,所以存储位置为:[0-1] */
short math_grade; /*同上,这个成员的有效对齐值为2,偏移地址为2的整数倍,存储位置为:[16-17]*/
double sum_grade; /*同上,这个成员的占字节数(自身对齐值)为8,我们可以算出这个成员的有效对齐值为8,他的偏移地址(相对于结构体的起始地址而言)为8的整数倍,所以其存储位置为[8-15] */
char Chinese_grade; /*这个成员的有效对齐值为1,偏移地址为1的整数倍,所以存储位置为:[18] */
}student3;
/*最后我们要算结构体的总大小,由上面段话我们可以知道,这个结构体的自身对齐值(其成员的自身对齐值中的最大者)为8(最大的是那个double型的成员),结构体的指定对齐值也是8(VS默认),所以这个结构体的有效对齐值是8(两个值中的最小者),所以结构体的大小一定是这个有效对齐值的整数倍, 成员存储位是到了[18],所以按8的整数倍补齐,结构体大小就为24; */
double b; /*有效对齐值是8, 存储在[8-15]*/
char c[9]; /*把他的自身对齐值看为9,所以有效对齐值为8,所以存储在[16-24],
};
/* 最后,结构体的有效对齐值为8,根据有效对齐值整数倍算,,D占的字节数为32.
明白了吧
同理:struct D
{
int a; /*有效对齐值为4, 存储在[0-3]*/ 所以所占的字节数为24.
如果能把下面这个结构体的大小算对的话,相信你应该已经理解了上面的话了:
二、结构体对齐参数按照默认的4字节对齐(指定对齐值),gcc默认方式
class TestC {
public:
char a;
short b;
char c;
};
这个类的大小是多少:
解答:
class TestC
{
public:
char a; //第一个成员,放在[0]偏移的位置,
short b; //第二个成员,自身长2,指定对齐值为 4,取2,按2字节对齐,所以放在偏移[2,3]的位置。
char c; //第三个,自身长为1,放在[4]的位置。
};
//整个类的大小是5字节,按照min(sizeof(short),4)字节对齐,也就是2字节对齐,结果是6
//所以sizeof(TestC)是6