结构体在内存中的存储+位域分配

来源:互联网 发布:基于内容的推荐算法 编辑:程序博客网 时间:2024/05/11 22:12

结构体在内存中的存储问题:

结构体是一种比较复杂的结构,一个结构体中可以定义多种不同的类型,不单单是基本数据类型如int,float,char 等,还可以在结构体中定义结构体,指针等复杂的数据结构。下面就来分析下,结构体在内存中的分配空间的问题。

首先,在内存中遵循2个大的原则:

1.不同的数据类型的数据,总是一个个的存储到内存中的,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始(以结构体变量首地址为0计算)。因此,存储可能是不连续的。对于不同类型,很可能是不连续的。

2. 对计算出的存储单元进行检查,看其是否为所有元素中占用空间最大的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍。

下面以例子分析:

先进行说明,在32位机器上,基本数据类型占的位数 (根据编译器的不同而不同)

char--1字节(8位), unsigned char--1字节(8位),

short--2字节(16位),unsigned short--2字节(16位)

int --4字节(32位), unsigned int --4字节(32位),

long--4字节(32位),unsigned long--4字节(32位),

float--4字节(32位),double--8字节(64位)

言归正传,定义结构体

struct
{
    char a;
    int  b;
    double c;
}T1;

sizeof(T1)=16,并不是1+4+8=13,关键就在于第一条规则,char的1个字节位于结构体的第0号字节。下面分配int的4字节,会以4字节为单位存储,因此会从第4个字节开始存储,现在0~7字节均已被占用,分配double会以8字节为单位,此时恰好会从第8号字节开始存储。因此总共占用了16字节的空间。

当结构体中变量定义的位置不一样时,所分配的空间也是不一样的。如

struct
{
    char a;

   double c;

    int  b;
}T1;

sizeof(T1)=24,应该是8+8+4=20,似乎又与第一条规则违背。那么引入第二条规则。20不是占用空间最大的元素的长度(8)的整数倍,则补齐,再加4字节。为8+8+4+4=24。

除了基本数据类型,对于较复杂的那么含有指针、数组或是其它结构体变量或联合体变量时该如何呢?

1.包含指针类型的情况。只要记住指针本身所占的存储空间是4个字节就行了,而不必看它是指向什么类型的指针。

            struct             struct                struct

            {                     {                      {     

                char *a;        int *b;             double *c;

            }T1;                }T2;                 }T3;

    经测试,可知sizeof(T1)、sizeof(T2)和sizeof(T3)的值都为4。

 

2.

 struct 

 {

    char a;

     int b;

    double c;

}T1;

 struct                                   

{

char a;

 T1 b;

 }T2;

经测试,可知sizeof(T1)为16,即为4+4+8

 sizeof(T2)为24,在存放第二个元素b时的初始位置是在double型的长度8的整数倍处,而非16的整数倍处,即系统为b所分配的存储空间是第8~23个字节。即为8+16=24。

如果将T2的两个元素char型的a和T1型的b调换定义顺序,则系统为b分配的存储位置是第0~15个字节,为a分配的是第16个字节,加起来一共17个字节,不是最长基本类型double所占宽度8的整数倍,因此要补齐到8的整数倍,即24。测试后可得sizeof(T1)的值为24。

由于结构体所占空间与其内部元素的类型有关,而且与不同类型元素的排列有关,因此在定义结构体时,在元素类型及数量确定之后,我们还应该注意一下其内部元素的定义顺序。

位域内存中存储 

C99规定int、unsigned   int和bool可以作为位域类型。但编译器几乎都对此作了扩展,允许其它类型类型的存在。
如果结构体中含有位域(bit-field),总结规则如下
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式;
4)如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,且应尽量节省内存。
备注:当两字段类型不一样的时候,对于不压缩方式。

 

 

 

原创粉丝点击