内存对齐
在32位系统下,gcc的对齐方式为1,2,4,默认为4字节对齐。
在64为系统下,gcc的对齐方式为1,2,4,8,默认为8字节对齐。
union变量所占用的内存长度等于最长的成员的内存长度。
struct和class内存中存储形式一样(函数不占内存空间)。
union
当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体(union)。在C Programming Language 一书中对于联合体是这么描述的:
1)联合体是一个结构;
2)它的所有成员相对于基地址的偏移量都为0;
3)此结构空间要大到足够容纳最"宽"的成员;
4)其对齐方式要适合其中所有的成员;
下面解释这四条描述:
由于联合体中的所有成员是共享一段内存的,因此每个成员的存放首地址相对于于联合体变量的基地址的偏移量为0,即所有成员的首地址都是一样的。为了使得所有成员能够共享一段内存,因此该空间必须足够容纳这些成员中最宽的成员。对于这句“对齐方式要适合其中所有的成员”是指其必须符合所有成员的自身对齐方式。
下面举例说明:
如联合体
union U
{
char s[9];
int n;
double d;
};
s占9字节,n占4字节,d占8字节,因此其至少需9字节的空间。然而其实际大小并不是9,用运算符sizeof测试其大小为16.这是因为这里存在字节对齐的问题,9既不能被4整除,也不能被8整除。因此补充字节到16,这样就符合所有成员的自身对齐了。从这里可以看出联合体所占的空间不仅取决于最宽成员,还跟所有成员有关系,即其大小必须满足两个条件:
1)大小足够容纳最宽的成员;
2)大小能被其包含的所有基本数据类型的大小所整除。
union联合体占用内存空间的大小的计算
1 代码
#include<iostream>
using namespace std;
union A{
int a[5];
char b;
double c;
};
int main(){
cout<<sizeof(A)<<endl;
return 0;
}
2 运行
[root@localhost charpter01]# g++ 0114.cpp -o 0114
[root@localhost charpter01]# ./0114
24
3 说明
union中变量同用内存,应以最长的为准,可是结果不是预想的20(5*4),这是因为公用体中变量的默认内存对齐方式,必须是以最长的double(8byte)对齐,也就是说应该是sizeof(A)=24.所以将公用体中int a[5]修改为int a[6]后,结果还是24.但是,如果将int a[5]修改为int a[7],结果将变成32.
struc还有一种:位域操作法
我们都知道在数据类型中,char类型占1个字节,short占2个字节,int占4个字节,long占8个字节等等。
在计算结构体大小时需要考虑其内存布局,结构体在内存中存放是按单元存放的,每个单元多大取决于结构体中最大基本类型的大小,下面我们看几个例子:
例子1:
struct A
{
char a;
int b;
short c;
}str1;
这里char占1个字节,int占4个字节,short占2个字节,按单元存放如下图:
a | |||
b | b | b | b |
c | c |
由于a占用了1个字节,b存不下,所以开辟新的单元存放b,然后再开辟新的单元存放c。
从这里可以看出结构体在内存中是按单元存放的,总占用字节数就是3*4=12。
例子2:
truct B
{
char a;
short c;
int b;
}str2;
存放如图:
a | c | c | |
b | b | b | b |
在这里由于b占用4个字节,而a和c总共才占用3个字节,足够c存放,所以c存放在a的后面,再开辟新的单元存放b。
此例中占用字节数为2*4=8。
例子3:
struct c
{
char a;
char b[2];
char c[4];
}str3;
存放如图:
a | b | b | c | c | c | c |
这里由于数据类型都为char类型,故不必再开辟新的单元,一行存完。
占用字节数为1*1+2*1+4*1=7。
综上所述,结构体在内存中存放是按单元存放的,所开辟单元的最大长度取决于占字节最大的数据类型,此外我们可以发现存储顺序对空间的使用率有一定的影响。
从以上三例可以看出,第一种最浪费空间;第三种最节省空间,但全使用相同类型,丢失了字段本生的数据类型,不方便使用;第二种介于第一种和第三种写法之间,其空间上比较紧凑,同时又保持了结构体中字段的数据类型。大家可以尝试用sizeof()去深入了解结构体中的按单元存放。
一个混合结构体大小的计算
1 代码
#include<iostream>
using namespace std;
typedef union{
long i;
int k[5];
char c;
} UDATE;
struct data{
int cat;
UDATE cow;
double dog;
}too;
UDATE temp;
int main(){
cout<<sizeof(struct data)+sizeof(temp)<<endl;
cout<<sizeof(struct data)<<endl;
cout<<sizeof(temp)<<endl;
return 0;
}
2 运行
[root@localhost charpter01]# g++ 0116.cpp -o 0116
[root@localhost charpter01]# ./0116
64
40
24
3 说明
sizeof(temp)=24在以前示例中已经解释。
我们看看sizeof(struct data)的计算。cat占用4个字节,cow占用24个字节。因为cow是8字节对齐,所以cat后要填充4个字节,即cat和cow共占用4+4+24=32字节。
dog占8字节,从32字节开始,已对齐,所以共40个字节。