sizeof(struct)与sizeof(union)

1字节是8位,一般32位机子上各个数据类型所占的存储空间如下:
char:8位
short:16位
int:32位
long:32位
unsigned long:32位
long long:64位
float:32位
double:64位
long double:64位
指针:32位

64位机器上各个数据类型所占的存储空间如下:
char:8位
short:16位
int:32位
long:64位
unsigned long:64位
long long:64位
float:32位
double:64位
long double:128位
指针:64位

注:静态成员不占用结构内存
1、sizeof()函数就是计算所占内存字节大小,
2、联合和结构体都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合只存放了一个被选中的成员, 而结构体的所有成员都存在。
3、对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构体的不同成员赋值是互不影响的。
下面对结构体与联合分四种情况看:
1、struct占用内存大小(sizeof(struct))
请牢记以下3条原则:(在没有#pragma pack(n)宏的情况下

一:数据成员对齐规则:结构体(struct)的数据成员,第一个数据成员放在offset为0的地方,之后的每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机子上为4字节,所以要从4的整数倍地址开始存储)。

二:结构体作为成员:如果一个结构体里同时包含结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储(如struct a里有struct b,b里有char,int ,double等元素,那么b应该从8(即double类型的大小)的整数倍开始存储)。

三:结构体的总大小:即sizeof的结果。在按之前的对齐原则计算出来的大小的基础上,必须还得是其内部最大成员的整数倍,不足的要补齐(如struct里最大为double,现在计算得到的已经是11,则总大小为16)。

具体例子:

typedef struct bb
{
    int id;             //[0]....[3]      表示4字节
    double weight;      //[8].....[15]      原则1
    float height;      //[16]..[19],总长要为8的整数倍,仅对齐之后总长为[0]~[19]为20,补齐[20]...[23]     原则3
}BB;

typedef struct aa  
{   
    int  id;         //[0]...[3]          原则1  
    double score;     //[8]....[15]      
    short grade;    //[16],[17]          
    BB b;             //[24]......[47]       原则2(因为BB内部最大成员为double,即8的整数倍开始存储)  
    char name[2]; //[48][49]
}AA; 

int main()
{
    cout<<sizeof(AA)<<" "<<sizeof(BB)<<endl;
    return 0;
}

输出结果为56 24
以上结果是在没有#pragma pack(n)宏的情况下,现在来讲讲关于#pragma pack(n)。

编译器中提供了#pragma pack(n)来设定变量以n字节对齐方式。//n为1、2、4、8、16…

n字节对齐就是说变量存放的起始地址的偏移量有两种情况:
第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,即该变量所占用字节数的整数倍;
第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。

结构的总大小也有个约束条件,分下面两种情况:
第一、如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;
第二、如果n小于该变量的类型所占用的字节数必须,则大小为n的倍数。

所以在上面的代码前加一句#pragma pack(1),

则代码输出为bb:(0~3)+(4~11)+(12~15)=16;
aa:(0~3)+(4~11)+(12~13)+(14~29)+(30~31)=32,也就是说,#pragma pack(1)就是没有对齐规则。

再考虑#pragma pack(4),bb:(0~3)+(4~11)+(12~15)=16;aa:(0~3)+(4~11)+(12~13)+(16~31)+(32~33)=36

2、union占用内存大小(sizeof(union))
联合表示几个变量共用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量。在union中,所有的成员共用一个空间,并且同一时间只能储存其中一个成员变量的值。当一个联合被声明时, 编译程序自动地产生一个变量, 其长度为联合中元类型(如数组,取其类型的数据长度)最大的变量长度的整数倍,且要大于等于其最大成员所占的存储空间。

union foo
{
char s[10];
int i;
}

在这个union中,foo的内存空间的长度为12,是int型的3倍,而并不是数组的长度10。若把int改为double,则foo的内存空间为16,是double型的两倍。

union   mm{  
  char   a;//元长度1        1
  int   b[5];//元长度4     20
  double   c;//元长度8     8
  int   d[3];              12
  };  

所以sizeof(mm)=8*3=24;
3、当在联合中包含结构体时,如下:

struct inner
{
   char      c1;
   double   d;
   char     c2;
  };

union data4
{
     struct   inner t1;
      int           i;
      char        c;
};

由于data4共用体中有一个inner结构体,所以最大的基本数据类型为double,因此以8字节对齐。共用体的存储长度取决于t1,而t1长度为24,因此sizeof(uniondata4)的值为24.
4、当在结构体中包含联合时
联合在结构体里的对齐地址为联合本身内部所对齐位数,如下:

typedef union{
    long i;
    int k[5];
    char c;
}DATE;
struct data{
    int cat;
    char cc;
    DATE cow;
    char a[6];
};

sizeof(DATE)=20, 而在结构体中中是4+1+3(补齐4对齐)+20+6+2(补齐4对齐)=36;
下面再看一个经典的笔试题:
1、32位机器上定义如下结构体:

struct xx 
{   long long _x1; 
    char _x2; 
    int _x3; 
    char _x4[2]; 
    static int _x5; 
 }; 
int xx::_x5;

请问sizeof(xx)的大小是()
A. 19  B. 20  C. 15  D. 24

解析:选D。首先_x5是静态变量可以不用管它,其次是要考虑字节对齐的问题。对于结构体中没有含有结构体变量的情况,有两条原则:1)结构体变量中成员的偏移量必须是成员大小的整数倍;2)结构体的最终大小必须是结构体最大简单类型的整数倍。x1的偏移量是0,长度是8,符合;x2的偏移量是8,长度是1,符合;x3的偏移量是9,长度是4,不符合,需要在x2之后填充3字节使得x3的偏移量达到12;x4的偏移量是16,长度是2,符合;此时总长度为(8)+(1+3)+(4)+(2)=18,而最大简单类型为long long长度为8,因此需要在x4之后再填充6字节,使得总长度达到24可被8整除。因此sizeof(xx)的结果为24。
每个元素的起始偏移地址要能被其类型大小整除,结构体整体大小要能被结构体中最大数据类型整除,静态成员不占用类空间,要注意自身是和8对齐的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值