数据结构还有变量等等都需要占有内存,在很多系统中,它都要求内存分配的时候要对齐,这样做的好处就是可以提高访问内存的速度。
#include <iostream>
2 using namespace std;
3
4 struct X1
5 {
6 int i;//4个字节
7 char c1;//1个字节
8 char c2;//1个字节
9 };
10
11 struct X2
12 {
13 char c1;//1个字节
14 int i;//4个字节
15 char c2;//1个字节
16 };
17
18 struct X3
19 {
20 char c1;//1个字节
21 char c2;//1个字节
22 int i;//4个字节
23 };
24 int main()
25 {
26 cout<<"long "<<sizeof(long)<<"/n";
27 cout<<"float "<<sizeof(float)<<"/n";
28 cout<<"int "<<sizeof(int)<<"/n";
29 cout<<"char "<<sizeof(char)<<"/n";
30
31 X1 x1;
32 X2 x2;
33 X3 x3;
34 cout<<"x1 的大小 "<<sizeof(x1)<<"/n";
35 cout<<"x2 的大小 "<<sizeof(x2)<<"/n";
36 cout<<"x3 的大小 "<<sizeof(x3)<<"/n";
37 return 0;
38 }
输出的结果:
1 long 4
2 float 4
3 int 4
4 char 1
5 x1 的大小 8
6 x2 的大小 12
7 x3 的大小 8
http://www.cppblog.com/cc/archive/2007/09/17/10765.html
在定义结构体x1,x2,x3时,由于变量的顺序不同,而导致分配的内存不同
内存是一个连续的块, 以每4个字节为一个对齐单位,来看一下x1,x2,x3在内存中的布局
对于x1,第一个是int型,它占4个字节,所以前面4格就满了,第二个是char型,它占第二个4字节组块的第一格,第三个是char型,它占第二个4字节组块的第二格,因为有内存对齐,所以输出结果为8而不是6.
对于x2,第一个类型是char型,它占用一个字节,所以它首先排在第一组块的第一个格子里面,第二个是Int类型,它占用4个字节,第一组块已经用掉一格,还剩3格,肯定是无法放下第二Int类型的,因为要考虑到对齐,所以不得不把它放到第二个组块,第三个类型是Char类型,跟第一个类似。所因为有内存分块对齐,我们的内存就不是8个格子了,而是12个了
当数组作为函数的参数传递时,该数组自动退化为同类型的指针。
如void Funct(char a[100])
{
cout<<sizeof(a)<<endl;//输出结果为4
}
而对于
struct
{
char a;
double b;
char c;
}
这里内存默认对齐字节数是8字节,所以结构体所占的字节数是24.
深入理解字节对齐:
结构体是种复合数据类型,其成员由基本数据类型构成(short,int,long,float,double,char),也可以是复合数据类型的数据单元(数组,联合,结构等),编译器为结构的每个成员按自然边界分配空间 ,各个成员按照它们被声明的顺序在内存中顺序存储,为了使cpu对变量加快访问,变量的起始地址应该具有某种特性,即所谓的对齐,如4字节的int型,其起始地址应该位于4字节的边界上,即能够被4整除。
字节对齐的作用:便于cpu快速访问,利用字节对齐合理的节省存储空间
对于32位机器来说,4字节对齐能够使cpu的访问速度提高,如果跨越了4字节边界存储,那么cpu就要读取2次,效率降低了。如果在32bit中使用1字节或2字节对齐,反而使处理器 速度降低了。所以要考虑处理器的类型。另外,也要考虑 编译器的类型,vc,gcc默认都是4字节对齐
更改c编译器的缺省字节对齐方式:
缺省条件下,c编译器为每个变量或数据单元按自然边界条件分配空间
1.使用伪指令:#program pack(n)//c编译器按n个字节对齐
#program pack()//取消自定义字节对齐方式
2._attribute(alligned(n)),//让所有的结构成员对齐在n字节的自然边界上,如果结构中有 成员的长 度大于n,则按最大成员的长度来对齐
_attribute_((packed)),//取消编译过程的优化对齐,按实际占用字节数对齐。
举例说明:
struct
{
char a;
short b;
float c;
char d;
}
编译器默认情况下对结构体做自然边界对齐,结构的第一个成员a,其偏移地址为0,占用 1个字节,第二个成员为b,其起始地址必须2字节对界。因此编译器在a和b之间填充一个空字节,结构的第3个成员和第4个成员恰好落在自然边界上,在结构中,第3个成员c要求4字节对齐,为该结构中所有成员要求的最大边界单元,因而该结构的自然边界对界条件是4字节,整个结构所占空间为12字节
如添加#program pack(1),整个结构所占字节为8字节
#program pack (2),。。。。。。。。。10字节
32位机器上各个基本数据类型所占的长度:
char 1 (有符号无符号相同)
short 2 (有符号无符号相同)
int 4 (有符号无符号相同)
long 4 (有符号无符号相同)
float 4
double 8
编译器按什么样的原则对齐:
首先看一下4个基本概念,
1.数据自身对齐值:char 1,short 2,int long float 4
2.结构体或类的自身对齐值:其成员中自身对齐值最大的那个
3.指定对齐值:#program pack(value) 对齐值为value
4.数据成员,结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个
有效对齐值N是最终决定数据存储方式的值。有效对齐N,表示“对齐在N上”,也就是说该数据的起始地址%N=0.而数据结构中的数据变量都是按定义的顺序来排放的,结构体的成员要对齐,结构题本身也要根据自身的对齐值圆整(就是结构体成员所占的总长度是结构体有效对齐值的整数倍)