liyuxia713

蹒跚前行者

常用链接

统计

Algorithms

C++

最新评论

sizeof:(含位域)结构体内存对齐,压缩存储

在此特别感谢在百度知道里帮我解答疑惑的confuciuskg
注:没有额外声明的结果均是在VC++环境中测试得到的结果。
1. sizeof 给出其操作数存储字节大小。
cout << " sizeof: " << endl;
    cout 
<< "char = " << sizeof(char<< endl; //1
    cout << "short int = " << sizeof(short int<< endl; //2
    cout << "unsigned short = " << sizeof(unsigned short<< endl; //2
    cout << "int = " << sizeof(int<<endl; //4
    cout << "unsigned int = " << sizeof(unsigned int<< endl; //4   
    cout << "long int = " << sizeof(long int<< endl; //4
    cout << "unsigned long = " << sizeof(unsigned long<< endl; //4
    cout << "float = " << sizeof(float<< endl; //4
    cout << "double = " <<sizeof(double<< endl; //8
    cout << "long double = " << sizeof(long double<< endl; //12
    double *a0;
    cout 
<< "double *a0 = " << sizeof(a0) << endl; //4, 因为地址是int类型
    double b0[10];
    cout 
<< "double b0[10] = " << sizeof(b0) << endl; //8*10=80
    struct c0 {    };
    cout 
<< "struct c0{}; = " << sizeof(c0) << endl; //1  空的struct和结构体类型长度为1
    char func(int a);
    cout 
<< "char func(int a); = " << sizeof(func(1)) <<endl; //1  求的是函数返回类型的长度
2. 内存对齐:
struct T
    
{
        
int i;
        
char j;
    }
;
    cout 
<< " struct T{int i; char j;} = " << sizeof(T) <<endl; //8
概念:实际的计算机系统对基本数据类型在内存中存放有限制。他们要求这些数据的首地址是某个数k的倍数,k被称作对齐模数(alignment modulus).
作用:一是简化处理器与内存之间传输系统的设计(这个我是不懂的);二是提升读取数据的速度。
对齐准则:
对于VC:
a. 结构体变量的首地址能被其最宽数据类型成员的大小所整除。这个最宽数据类型大小作为对齐模数。
b. 结构体每个成员相对于结构体首地址的偏移量(offset)都是这个成员大小的整数倍。
c. 结构体的总大小对齐模数的倍数。
对于GNU GCC:
区别是其对齐模数对大只能是4,根据上面的原则得出大于4的值时以4替代。
struct T1
    
{
        
char c;
        
double d;
        
int i;
    }
;
    cout 
<< "struc T1{char c; double d; int i;} = " << sizeof(T1) << endl; // vc6.0环境:24
3. 结构体位域:
struct N
{
   
char c:2;
   
double i;
   
int c2:4;
}
;
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位(一个字节8个二进制位)。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。
注意:一个位域必须存储在同一个字节中,不能跨字节。一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。(从这里也能看出一个位域不能超过8)。
4.含位域结构体内存对齐
a. 如果相邻位域类型相同,位宽之和小于类型的sizeof大小,则后面的字段紧邻前一个字段存储,直到不能容纳为止;
b. 如果相邻位域类型相同,位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
c. 如果相邻位域类型不用,则vc6采取不压缩方式,dev-c++ 和GCC都采取压缩方式。
5. 非压缩存储
 struct T0
    
{
        
char c:2;
        
int i:1;
    }
;
    cout 
<< "struct T0{ char c:2; int i:1;} = " << sizeof(T0) << endl; //dev c++:4  vc6:8
依然要满足不含位域结构体内存对齐准则第2条,i成员相对于结构体首地址的偏移应该是4的整数倍,所以c成员后要填充3个字节,然后再开辟4个字节的空间作为int型,其中4位用来存放i,所以上面结构体在VC中所占空间为8个字节;而对于采用压缩方式的编译器来说,遵循不含位域结构体内存对齐准则第2条,不同的是,如果填充的3个字节能容纳后面成员的位,则压缩到填充字节中,不能容纳,则要单独开辟空间,所以上面结构体T0在GCC或者Dev-C++中所占空间应该是4个字节。
6. 嵌套结构体的sizeof:  对齐模数的选择只能是根据基本数据类型,所以对于结构体中嵌套结构体,只能考虑其拆分的基本数据类型。对于对齐准则中的第2条,也是根据内层结构体中基本数据类型的最宽长度(而不是网上大量转载的要将整个结构体看成是一个成员,成员大小按照该结构体根据对齐准则判断所得的大小)。给个例子予以说明:
union a 
    
{
        
int a_int1;
        
double a_double;
        
int a_int2;
    }
;

    typedef 
struct
    
{
        a a1;
        
char y;
    }
 b;

    
class c //嵌套
    {
    
public:
         
double c_double;
        b b1;
        a a2;
    }
c1;
    cout 
<< "a = " << sizeof(a) << endl; //8
    cout << "b = " << sizeof(b) << endl; //16,平移了0位至第9字节,而不是17字节
    cout << "c = " << sizeof(c) << endl; //32,
    cout  << &(c1.c_double) << "," << &(c1.b1) << "," << &(c1.a2) <<endl;    // 0012FF0C, 0012FF14, 0012FF24
 
7. 类对象的sizeof:类对象在内存中存放的方式和结构体类似,这里就不再说明。需要指出的是,类对象的大小只是包括类中非静态成员变量所占的空间,因为静态变量的存储位置与结构或者类的实例地址无关。果有虚函数,那么再另外增加一个指针所占的空间即可。
8. 一些修改对齐模数的命令
#pragma pack(push) //保存对齐状态
#pragma pack(n) /设置对齐模数(选择n和一般情况下选出来的模数的较小者做对齐模数)
#pragma pack(pop) //恢复对齐状态

posted on 2009-04-25 11:33 幸运草 阅读(3289) 评论(0)  编辑 收藏 引用 所属分类: C++


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理