内存对齐及位域

来源:互联网 发布:java 对话框 编辑:程序博客网 时间:2024/06/05 16:45
内存对齐”应该是编译器的“管辖范围”。
编译器为程序中的每个“数据单元”安排在适当的位置上。
但是C语言的一个特点就是太灵活,太强大,它允许你干预“内存对齐”
内存对齐是个什么:
为什么要内存对齐:
#include<iostream>
using namespace std;
struct A{
    char a;
    int b;
    short c;
};


struct B{
    short c;
    char a;
    int b;
};
int main(){
    cout<<sizeof(A)<<endl;
    cout<<sizeof(B)<<endl;
    return 0;
}
以上结构体变量数量类型相同。但是sizeof却不同,


    sizeof(A) is 12


    sizeof(B) is  8
这是为什么呢?  结果是因为内存对齐,在程序中编译器对程序中每个数据单元安排在合适的位置上
A:char占一个字节,起始偏移为零,int 占四个字节,min(8,4)=4;所以应该偏移量为4,所以应该在char后面加上三个字节,不存放任何东西,short 占两个字节,min(8,2)=2;所以偏移量是2的倍数,而short偏移量是8,是2的倍数,所以无需添加任何字节,所以第一个规则对齐之后内存状态为  0xxx|0000|00    


  此时一共占了10个字节,但是还有结构体本身的对齐, min(8,4)=4;所以总体应该是4的倍数,所以还需要添加两个字节在最后面,所以内存存储状态变为了 0xxx|0000|00xx   一共占据了12个字节
来看看内存对齐的规则,每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。


1.对于结构的各个成员,第一个成员位于偏移为0的位置,以后的每个数据成员的偏移量必须是  min(#pragma pack()指定的数,这个数据成员的自身长度)的倍数


2.在所有的数据成员完成各自对齐之后,结构或联合体本身也要进行对齐,对齐将按照 #pragram pack 指定的数值和结构或者联合体最大数据成员长度中比较小的那个  也就是  min(#pragram pack() , 长度最长的数据成员);


   #pragram pack(n)  表示的是设置n字节对齐,vc6默认的是8
那么为什么需要内存对齐呢?内存对齐有什么作用?
1.平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常


  2.硬件原因:经过内存对齐之后,CPU的内存访问速度大大提升。具体原因接下来解释








我们普通程序员心中的内存印象,由一个个字节组成,但是CPU却不是这么看待的






cpu把内存当成是一块一块的,块的大小可以是2,4,8,16 个字节,因此CPU在读取内存的时候是一块一块进行读取的,块的大小称为(memory granularity)内存读取粒度。
位域:
位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。
例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。
为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。
所谓“位域”是把一个字节中的二进位划分为几 个不同的区域, 并说明每个区域的位数。
每个域有一个域名,允许在程序中按域名进行操作。 
这样就可以把几个不同的对象用一个字节的二进制位域来表示。
位域定义的几点说明
1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
2. 位域的长度不能大于指定类型固有长度,比如说int的位域长度不能超过32,bool的位域长度不能超过8。例如,在第3行代码int z:33中,定义整型变量z为33位,也就是超过了4字节,这是不合法的,会造成越界,所以程序在编译时就会报错。
3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
struct k
{int a:1; int :2; /*该2位不能使用*/ int b:3; int c:2};


位域变量的说明
与结构变量说明的方式相同。 
可采用先定义后说明,同时定义说明或者直接说明这三种方式。
例如:
struct bs
{int a:8;int b:2;int c:6;}data, *bsp;
说明data为bs变量,共占2个字节。其中位域a占8位,位域b占2位,位域c占6位。位域也是可以使用指针的。
赋值不能超过该位域的允许范围。
原创粉丝点击