漫谈c语言结构体
程序的运行结果如下(注意:括号内的数据是成员变量的地址的十进制形式):
2.结构体成员变量内存对齐
首先,我们来分析一下上面程序的运行结果。前三行说明在我的程序中,char型占1个字节,short型占2个字节,long型占4个字节。char_short_long、long_short_char和char_long_short是三个结构体成员相同但是成员变量的排列顺序不同。并且从程序的运行结果来看,
Size of char_short_long =8bytes
Sizeof long_short_char=8bytes
Sizeof char_long_short=12bytes//比前两种情况大4byte!
并且,还要注意到,1 byte (char)+2byte(short)+4 byte(long) = 7 byte,而不是8 byte。
所以,结构体成员变量的放置顺序影响着结构体所占的内存空间的大小。一个结构体变量所占内存的大小不一定等于其成员变量所占空间之和。如果一个用户程序或者操作系统(比如uC/OS-II)中存在大量结构体变量时,这种内存占用必须要进行优化,也就是说,结构体内部成员变量的排列次序是有讲究的。
结构体成员变量到底是如何存放的呢?
在这里,我就不卖关子了,直接给出如下结论,在没有#pragmapack宏的情况下:
原则1结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。
原则2结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
*原则3结构体作为成员时,结构体成员要从其内部最大元素大小的整数倍地址开始存储。(structa里存有structb,b里有char,int,double等元素时,那么b应该从8的整数倍地址处开始存储,因为sizeof(double)=8bytes)
这里,我们结合上面的程序来分析(暂时不讨论原则3)。
先看看char_short_long和long_short_char这两个结构体,从它们的成员变量的地址可以看出来,这两个结构体符合原则1和原则2。注意,在char_short_long的成员变量的地址中,char_short_long.s的地址是1244994,也就是说,1244993是“空的”,只是被“占位”了!
再看看char_long_short这个结构体,char_long_short的地址分布情况如下表:
成员变量 | 成员变量十六进制地址 | 成员变量十进制地址 |
char_long_short.c | 0x0012FF2C | 1244972 |
char_long_short.l | 0x0012FF30 | 1244976 |
char_long_short.s | 0x0012FF34 | 1244980 |
可见,其内存分布图如下,共12bytes:
地址 | 1244972 | 1244973 | 1244974 | 1244975 | 1244976 | 1244977 | 1244978 | 1244979 | 1244980 | 1244981 | 1244982 | 1244983 |
成员 | .c | .l | .s | |||||||||
首先,1244972能被1整除,所以char_long_short.c放在1244972处没有问题(其实,就char型成员变量自身来说,其放在任何地址单元处都没有问题),根据原则1,在之后的1244973~1244975中都没有能被4(因为sizeof(long)=4bytes)整除的,1244976能被4整除,所以char_long_short.l应该放在1244976处,那么同理,最后一个.s(sizeof(short)=2bytes)是应该放在1244980处。
是不是这样就结束了?不是,还有原则2。根据原则2的要求,char_long_short这个结构体所占的空间大小应该是其占内存空间最大的成员变量的大小的整数倍。如果我们到此就结束了,那么char_long_short所占的内存空间是1244972~1244981共计10bytes,不符合原则2,所以,必须在最后补齐2个bytes(1244982~1244983)。
至此,一个结构体的内存布局完成了。
下面我们按照上述原则,来验证这样的分析是不是正确。按上面的分析,地址单元1244973、1244974、1244975以及1244982、1244983都是空的(至少char_long_short未用到,只是“占位”了)。如果我们的分析是正确的,那么,定义这样一个结构体,其所占内存也应该是12bytes:
struct//声明结构体char_long_short_new
{
charc;
charadd1;//补齐空间
charadd2;//补齐空间
charadd3;//补齐空间
longl;
shorts;
charadd4;//补齐空间
charadd5;//补齐空间
}char_long_short_new;
运行结果如下:
可见,我们的分析是正确的。至于原则3,大家可以自己编程验证,这里就不再讨论了。
所以,无论你是在VC6.0还是KeilC51,还是KeilMDK中,当你需要定义一个结构体时,只要你稍微留心结构体成员变量内存对齐这一现象,就可以在很大程度上节约MCU的RAM。这一点不仅仅应用于实际编程,在很多大型公司,比如IBM、微软、百度、华为的笔试和面试中,也是常见的。
本例完整的程序代码下载:http://www.51hei.com/f/cjgt.rar
c语言结构 相关文章:
- c语言结构体数组初始化(11-27)
- c语言结构体定义结构体(11-27)
- c语言定义结构体指针(11-27)
- 51单片机之C语言-4.3结构体(11-21)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
