转载请注明出处:
http://blog.chinaunix.net/uid-30008524-id-5663357.html
C里面的结构体和联合体都涉及到字节对齐的问题。
首先说一下结构体。结构体内存布局的规则是
1.以成员中最大的数据类型为步长分配内存块给结构体
2.每个成员存储的起始地址必须是自身类型的整数倍
比如说一个结构体
struct A
{
char a;
int b;
char c;
short d;
};
A里面最大的类型是int,4个字节,所以以4个字节为单位分配内存块给A。
先分配一个4个字节内存块给A,把A.a放进去,内存是这样的:(每个数字代表一个字节,1是有数据存放,*是没有数据存放)
1***
a
再放b,b有4个字节,放不下了,增加一个内存块,由于规则2,b必须在4的倍数地址开始存储,所以b放在第二个内存块中,放进来后内存是这样的:
1*** 1111
a b
再分配一个内存块放c,内存是这样的
1*** 1111 1***
a b c
再放d,2个字节,根据规则2,d放在最后两个字节
1*** 1111 1*11
a b c d
所以sizeof(A)=12
联合体
联合体的内存布局规则是
1.以成员中最大的数据类型为步长分配内存块给结构体(这条规则跟结构体一样)
2.能装下最大成员的最小内存
比如说一个联合体
union B
{
char a[10];
int 4;
};
按照规则2,至少要分配10字节内存才能放下a,然后根据规则1,每个内存块4个字节,B占用的内存要大于等于10,同时是4的倍数的最小值,所以B占用12字节。
我们来写个小程序验证一下。
-
#include "stdio.h"
-
#include "string.h"
-
struct A
-
{
-
int a;
-
char b;
-
short c;
-
};
-
union B
-
{
-
int a;
-
char b;
-
short c;
-
};
-
int main()
-
{
-
A a = {1,2,3};
-
A c = {1,2,3};
-
if(memcmp(&a,&c,8)==0)
-
printf("same");
-
else
-
printf("diff");
-
-
memset(&a,0,sizeof(a));
-
memset(&c,0,sizeof(c));
-
a.a = 1;a.b = 2;a.c = 3;
-
c.a = 1;c.b = 2,c.c = 3;
-
-
if(memcmp(&a,&c,8)==0)
-
printf("same");
-
else
-
printf("diff");
-
B b;
-
b.a = 1;b.b = 2;b.c = 3;
-
return 0;
-
}
在19行设置断点,然后运行,我们来看一下
a占用了8个字节,然后a.a放在内存低位,占4个字节,值为0x01,a.b值为0x02,放在第五个字节,a.c从第七个字节开始,占用两个字节,值为0x03.
内存布局简化为:
1111 1*11
注意那个未填充的*,显示是0x86,其实是随机的
我们对比一下a和c的空隙的地方
一个是0x86,一个是0x72.虽然a和c用同样的值去初始化,但其内部不是一模一样的,所以第20行用memcmp去对比a和c,会打印“diff”,程序继续运行,memset把a和c清零,再对a和c赋一样的值,此时再memcmp,得到是是“same”,因为空隙的地方已经被清零了。
再来看一下联合体b,b.a=1,b.b=2,b.c=3.对每个成员都赋值一遍
可以看到b占用4个字节,就是成员最大的数据类型int的大小。其内部值是3,就是b.c的值。
再看里面每个成员和b自身的起始地址
发现它们地址都是一样的,联合体的所有成员都和联合体共享一个起始地址,也就说,新的赋值会冲掉旧的赋值,所以b里面只存储了3,前面赋的1和2都被冲掉了。
阅读(3431) | 评论(0) | 转发(0) |