struct自己对齐是面试中几乎必问的问题,但是真正十分清楚的人感觉很少,包括我自己,没有特别花时间研究下。
为了提高CPU的存储速度,VC对一些变量的起始地址做了“对齐”处理。这里主要使用VC2013,系统win7-64位测试。g++之类的没有尝试过。
两条规则:
1.在默认情况下,VC规定各成员变量存放的起始地址,相对于结构起始地址的偏移量,必须为该变量的类型占用字节数的整数倍,如Char偏移量为sizeof(char)即1的倍数,int 偏移量应该是4的倍数,double应该是8的倍数,如果是struct,则根据struct的第一个成员类型进行判断。
如果到某个成员,该成员的地址偏移量不是size整数倍怎么办,那就需要对上一个成员结束位置开始,补齐字节,直到地址值偏移量是下一个成员size的整数倍。如果是数组当成连续的成员看待。如果上一个成员是struct,那么上一个struct的totalSize 要根据struct的maxSize独立计算,才能得到正确的偏移量。
2.结构占用的总空间大小应该为,结构中占用最大空间的类型所占用的字节数的整数倍。
这里我测试了一下,这个最大的占用空间的类型,应该指的是基本类型,比如一个数组char a[5],这种情况要分开来开,不能当成大小为5的数组,而是要看成5个char类型;另外如果有个成员是另一个struct,那么这个struct的大小也不能当做是占用最大空间的类型,而应该是struct中size最大的成员为准。
最后强调一句吧,如果struct A中有struct B,则开头看structB的第一个成员;如果struct B后有其他成员,那么计算偏移量时,前边的成员struct B 要当成独立个体计算(也就是说满足规则1,2)。最后计算struct A中maxSize类型时,要考虑struct B中的所有成员
事实胜于雄辩
// StructSize.cpp : 定义控制台应用程序的入口点。
//
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
// 空结构,空类,都是1
struct S0
{
};
/*
成员a类型char,偏移0,0是任何整数的整数倍,不补齐字节。
maxSize:sizeof(char) == 1
totalSize: 1 , totalSize % maxSize == 0,末尾不补字节
totalSize:1
*/
struct S1
{
char a;
};
/*
成员a:类型char,偏移0,0%1==0,不补字节。
成员b:类型char,偏移1=sizeof(a),1%1==0, 不补字节。
maxSize: sizeof(char) == 1
totalSize: 1+1=2 , totalSize % maxSize == 0,末尾补字节 +0
totalSize:2
*/
struct S2
{
char a;
char b;
};
/*
totalSize:3
*/
struct S3
{
char a;
char b;
char c;
};
/*
成员a:类型double,sizeof(double)==8,偏移0,0%8==0,不补字节。
成员b:类型char,偏移:8=sizeof(a),8%1==0, 不补字节。
maxSize: sizeof(double) == 8
totalSize: 8+1=9 , totalSize % maxSize != 0,末尾补字节 +7
totalSize: 9+7 = 16
*/
struct S4
{
double a;
char b;
};
/*
totalSize:8
*/
struct S5
{
int a;
char b;
};
/*
成员a:类型short,sizeof(short)==2,偏移0,0%2==0,不补字节。
成员b:类型char,偏移:2=sizeof(a),2%1==0, 不补字节。
maxSize: sizeof(short) == 2
totalSize: 2+1=3 , totalSize % maxSize == 3,末尾补字节 +1
totalSize: 2+1+1 = 4
*/
struct S6
{
short a;
char b;
};
/*
成员a:类型short,sizeof(char)==1,偏移0,0%1==0,不补字节。
成员b:类型int,偏移:1=sizeof(a),1%sizeof(int)==1, 补字节 +3。
maxSize: sizeof(int) == 4
totalSize: 1+3+4=8 , totalSize % maxSize == 0,末尾补字节 +0
totalSize:8
*/
struct S7
{
char a;
int b;
};
/*
totalSize:16
*/
struct S8
{
double a;
int b;
};
/*
成员a:类型拆成5个char看,size==5,补字节 +0。
成员b:类型int,偏移:5=sizeof(a),5%sizeof(int)==1, 补字节 +3。
maxSize: sizeof(int) == 4 (注意不是sizeof(a)==5)
totalSize: 5+3+4=12 , totalSize % maxSize == 0,末尾补字节 +0
totalSize:12
*/
struct S9
{
char a[5];
int b;
};
/*
成员a:3==sizeof(S3)
成员b:偏移:3=sizeof(a),3%sizeof(char)==0, 补字节 +0。
maxSize: sizeof(char) == 1 (注意,包括S3最大的结构)
totalSize: 3+1=4 , totalSize % maxSize == 0,末尾补字节 +0
totalSize: 4
*/
struct S10
{
S3 a;
char b;
};
/*
成员a:16==sizeof(S4)
成员b:偏移:16=sizeof(a),16%sizeof(char)==0, 补字节 +0。
maxSize: sizeof(double) == 8 (注意,包括S4最大的结构,double)
totalSize: 16+1=17 , totalSize % maxSize == 1,末尾补字节 +7
totalSize: 17+7=24
*/
struct S11
{
S4 a;
char b;
};
/*
成员a:8==sizeof(S5)
成员b:类型char,偏移:8=sizeof(a),8%sizeof(char)==0, 补字节 +0。
maxSize: sizeof(int) == 4 (注意,包括S5最大的结构,int)
totalSize: 8+1=9 , totalSize % maxSize == 1,末尾补字节 +3
totalSize: 9+3=12
*/
struct S12
{
S5 a;
char b;
};
//sizeof(STemp1)==7
struct STemp1
{
char a[7];
};
//sizeof(STemp2)==5
struct STemp2
{
char a[5];
};
/*
成员a:7==sizeof(STemp1)
成员b:偏移:7=sizeof(a),7%sizeof(double)==7, 补字节 +1。
maxSize: sizeof(double) == 8
totalSize: 7+1+8=16 , totalSize % maxSize == 0,末尾补字节 +0
totalSize: 16
*/
struct S13
{
STemp1 a;
double b;
};
/*
成员a:1==sizeof(char)
成员b:偏移:1,1%sizeof(char)==0, 补字节 +0 (STemp1 第一个成员是char,要分开来看)
成员c:偏移:8=1+sizeof(char)*7,8%sizeof(char)==0, 补字节 +0 (STemp2 第一个成员是char,要分开来看)
成员d:偏移:13=8 +sizeof(char)*5,13%sizeof(doulbe)==5, 补字节 +3
成员d:偏移:24=13+3 +sizeof(double),24%sizeof(char)==0, 补字节 +0
maxSize: sizeof(double) == 8
totalSize: 25=24+1 , totalSize % maxSize == 1,末尾补字节 +7
totalSize: 32
*/
struct S14
{
char a;
STemp1 b;
STemp2 c;
double d;
char e;
};
/*
成员a:sizeof(char)==1
成员b:偏移:1=sizeof(a),1%sizeof(double)==1, 补字节 +7。
成员c:偏移:16=1+7+8,16%sizeof(char)==0, 补字节 +0。
成员d:偏移:17=16+1,17%sizeof(int)==1, 补字节 +3。
成员e:偏移:24=17+3+4,24%sizeof(STemp2)==4, 补字节 +1。
maxSize: sizeof(double) == 8 (所有结构中找)
totalSize: 25 = 24+1 , totalSize % maxSize == 1,末尾补字节 +7
totalSize: 32 = 25+7
*/
struct S15
{
char a;
double b;
char c;
int d;
STemp2 e;
};
/*
成员a:1==sizeof(char)*3
成员b:偏移:3,1%sizeof(char)==0, 补字节 +0 (S7 第一个成员是char,要分开来看)
成员c:偏移:11=3+sizeof(S7),11%sizeof(double)==3, 补字节 +5 (S4 第一个成员是double,要分开来看)
成员d:偏移:32=11 + 5 +sizeof(S4),32%sizeof(int)==0, 补字节 +0 (S4 第一个成员是int,要分开来看)
成员e:偏移:40=32 +sizeof(S5),40%sizeof(char)==0, 补字节 +0
maxSize: sizeof(double) == 8
totalSize: 41=40+1 , totalSize % maxSize == 1,末尾补字节 +7
totalSize: 48
*/
struct S16
{
char a[3];
S7 b;
S4 c;
S5 d;
char e;
};
int _tmain(int argc, _TCHAR* argv[])
{
cout << "sizeof( S0 ) = " << sizeof(S0) << endl;
cout << "sizeof( S1 ) = " << sizeof(S1) << endl;
cout << "sizeof( S2 ) = " << sizeof(S2) << endl;
cout << "sizeof( S3 ) = " << sizeof(S3) << endl;
cout << "sizeof( S4 ) = " << sizeof(S4) << endl;
cout << "sizeof( S5 ) = " << sizeof(S5) << endl;
cout << "sizeof( S6 ) = " << sizeof(S6) << endl;
cout << "sizeof( S7 ) = " << sizeof(S7) << endl;
cout << "sizeof( S8 ) = " << sizeof(S8) << endl;
cout << "sizeof( S9 ) = " << sizeof(S9) << endl;
cout << "sizeof( S10 ) = " << sizeof(S10) << endl;
cout << "sizeof( S11 ) = " << sizeof(S11) << endl;
cout << "sizeof( S12 ) = " << sizeof(S12) << endl;
cout << "sizeof( S13 ) = " << sizeof(S13) << endl;
cout << "sizeof( S14 ) = " << sizeof(S14) << endl;
cout << "sizeof( S15 ) = " << sizeof(S15) << endl;
cout << "sizeof( S16 ) = " << sizeof(S16) << endl;
return 0;
}