C语言结构体大小你算对了吗
C语言中struct声明创建一个数据类型(结构体),能将不同类型的对象聚合到一个对象中,用名字来引用结构体的各个组成部分。结构体的所有组成部分都存放在一段连续的内存中。
如果创建一个结构体,其实际占用的内存空间大小是多少呢?示例代码如下:structS{inti;charc;intj;};
要正确计算结构体大小,首先需要了解数据对齐的原理。数据对齐
许多计算机系统对基本的数据类型的合法地址做了一些限制。要求某种类型对象的地址必须是某个值(通常为2、4、8)的倍数。这种对齐限制简化了形成处理器和内存系统之间接口的硬件设计。
对齐原则:任何占用K字节空间大小的基本对象,其地址必须是K的倍数。
那么,char类型数据存储地址必须是1的倍数。short类型数据存储的地址为2的倍数,以此类推。
确保每种数据类型都是按照指定方式来组织和分配,即每种类型的数据都满足它的对齐限制,就可以保证实施对齐。
对于包含结构体的代码,编译器可能需要在字段的分配中插入间隙,以保证每个结构成员都满足它的对齐要求。而结构体本身对它的起始地址也有一些对齐要求。
由此,编译器可能需要在结构体成员内存的分配中插入间隙,保证每个结构成员都满足它的对齐要求。或者需要在结构体的末尾加入填充,从而使得结构体数组中的每个元素都会满足它的对齐要求。结构体大小计算
情形一
结构体中间插入间隙,上述代码:structS{inti;charc;intj;};
如果编译器按照最小9字节分配,是不可能满足成员i和j的4字节对齐要求的。此时,编译器会在成员c和j之间插入一个3字节的间隙。结果j的偏移量为8,而整个结构体的大小为12。
情形二
另外一个示例如下,其大小是多少呢?structS2{inti;intj;charc;};
要正确计算这个结构体的大小,需要这样考虑:创建这个结构体的数组,每个数组元素都会满足它的对齐要求。
如果给这个结构体分配9个字节。考虑结构体数组structs2a〔4〕,就不能满足数组a的每个元素的对齐要求。假设数组的起始地址为x,则每个元素的地址分别为x、x9、x18、x27,有三个元素不满足对齐原则。
由此,编译器会为结构s2分配12个字节,最后三个字节是补充的空间(浪费的空间),即在结构体的末尾增加填充。
情形三
结构体成员是另外一个结构体时,示例如下:structsta{inti;intj;charc;};structstb{inti;charc;intj;charcc;structstatmp;};
结构体srb的大小是多少呢?
要计算这种类型的结构体,只需要把其中的结构体成员当成一个整体即可。
先忽略成员tmp,结构体stb的大小为16字节(中间和末尾均需要填充间隙);结构体sta的大小为12字节。从而可以计算得出,结构体stb的实际大小为161228字节。
情形四
使用编译指令,示例代码如下:pragmapack(1)structS3{inti;intj;charc;}pragmapack()
注意编译指令pragmapack的主要作用就是改变编译器的内存对齐方式。在不使用这条指令的情况下,编译器采取默认方式对齐。
此处的两条编译预处理指令,使得在这之间定义的结构体按照1字节方式对齐。在本例中,使用这两条指令的效果是,编译器不会在结构体尾部填充空间了。
这个结构体的大小为9字节。