struct结构体占内存大小计算

来源:互联网 发布:单片机编程有关的书 编辑:程序博客网 时间:2024/05/16 09:12

struct结构体占内存大小计算  

  

注意:struct 的{}后面要加上 ”;“

#include<stdio.h>
struct A
{
           int a;
          double b;
           char c;
};
struct B
{
           double b;
            char c;
            int a;
};
struct C
{
            int a;
            char c;
            double b;
};
int main(void)
{
          A aa;
          B bb;
          C cc;
          printf("A = %d\n", sizeof(aa));//结果:A = 24
          printf("B = %d\n", sizeof(bb));//结果:B = 16
          printf("C = %d\n", sizeof(cc));//结果:C = 16
          return 0;
}
int类型一般是占用四个字节,char类型一般占用一个字节,double类型一般占用8个字节。
1、结构体A首先给int a 分配四个字节,并且以4个字节对齐;然后给double b分配8个字节,发现以4个字节对齐不行,就以8个字节对齐,前面只有int a ,所以int a将占用8个字节;最后为了对齐,将给char c 也分配8给字节,所以结构体A占用了24个字节。
2、结构体B首先给double 分配8个字节,并且以8给字节对齐;然后给char c分配8给字节;最后给int a分配空间的时候发现,前面空有7个字节空间可以放下int a,int a 就和char c一起占用8个字节,所以结构体B占用了16个字节

而在GNU GCC编译器中,遵循的准则有些区别,对齐模数不是像上面所述的那样,根据最宽的基本数据类型来定。在GCC中,对齐模数的准则是:对齐模数最大只能是4,也就是说,即使结构体中有double类型,对齐模数还是4,所以对齐模数只能是1,2,4。而且在上述的三条中,第2条里,offset必须是成员大小的整数倍,如果这个成员大小小于等于4则按照上述准则进行,但是如果大于4了,则结构体每个成员相对于结构体首地址的偏移量(offset)只能按照是4的整数倍来进行判断是否添加填充。
看如下例子:

struct T
{
  char ch;
  double     ;
};
那么在GCC下,sizeof(T)应该等于12个字节。

 

struct结构体的大小计算:
struct 大小,与pack的大小(在程序中显示设置#pragma pack(),vc6.0默认大小为8)、结构中最大占用有关

struct A
{

 int a;     0-3

               4-7     要填充(padding)以保证内存对齐的原则
 double b; 8-15
 char c[9]; 16-24
};

首先给a分配内存,因为int占四个字节<pack大小(8个字节),所以按照4个字节对齐,起始位值为0,0%4=0,a最后占的内存为0-3;

接着给b分配内存,double占8个字节,所以按照8个字节对齐,起始位为8(8%8=0),b为8-15;

最后char占一个字节,所以c为16-24;

因此结构体A的大小为8+8+9 = 25;有因为25不是结构体中最大占用内存类型double类型大小(8)的整数倍,所以A最后的大小是32;

struct B

{
int a;   

double b;     
double c;    
char d;   

};

同理,按上面的分析方法确定各个变量在内存中的位置:
a,0-3;

  ,4-7;
b,8-15;
c,16-23;
d,24;

TOTAL = 25

25 不是8的倍数,所以最后B大小是32;

总结计算结构体的步骤

1.内存对齐与编译器设置有关,首先要搞清编译器这个默认值是多少

2.如果不想编译器默认的话,可以通过#pragma pack(n)来指定按照n对齐

3.每个结构体变量对齐,如果对齐参数n,变量所占字节数(m),内存地址的起始位置%min(n,m)=0。也就是最小化长度规则

4.结构体总大小: 对齐后的长度必须是成员中最大的对齐参数的整数倍。

5.补充:如果结构体A中还要结构体B,那么B的对齐方式是选它里面最长的成员的对齐方式

所以计算结构体大小要走三步,首先确定是当前程序按照几对齐(参照1,2点),接着计算每个结构体变量的大小和偏移(参照3,5),最后计算结构体总大小(参照4)。

 

如果结构体中含有位域(bit-field),那么VC中准则又要有所更改:
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式;
备注:当两字段类型不一样的时候,对于不压缩方式,例如:


struct N
{
  char c:2;
  int    i:4;
};

依然要满足不含位域结构体内存对齐准则第2条,i成员相对于结构体首地址的偏移应该是4的整数倍,所以c成员后要填充3个字节,然后再开辟4个字节的空间作为int型,其中4位用来存放i,所以上面结构体在VC中所占空间为8个字节;而对于采用压缩方式的编译器来说,遵循不含位域结构体内存对齐准则第2条,不同的是,如果填充的3个字节能容纳后面成员的位,则压缩到填充字节中,不能容纳,则要单独开辟空间,所以上面结构体N在GCC或者Dev-C++中所占空间应该是4个字节。

4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
备注:
结构体


typedef struct
{
   char c:2;
   double i;
   int c2:4;
}N3;

在GCC下占据的空间为16字节,在VC下占据的空间应该是24个字节。
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。

ps:


对齐模数的选择只能是根据基本数据类型,所以对于结构体中嵌套结构体,只能考虑其拆分的基本数据类型。而对于对齐准则中的第2条,确是要将整个结构体看成是一个成员,成员大小按照该结构体根据对齐准则判断所得的大小。 
类对象在内存中存放的方式和结构体类似,这里就不再说明。需要指出的是,类对象的大小只是包括类中非静态成员变量所占的空间,如果有虚函数,那么再另外增加一个指针所占的空间即可。 

原创粉丝点击