关于C语言中的对齐补齐

what

对齐,是C语言对结构体的一个内存优化策略。

计算机中内存空间都是按照字节划分的,从理论上讲对任何类型的变量的访问可以从任何地址开始,但是在程序实际编译过程中,编译器会对数据类型在编译过程中进行优化对齐,编译器会将各种类型数据按照一定的规则在空间上排列,而不是顺序的排放,这就是内存字节对齐。

使用场景:

我们声明一个如下结构体:

typedef struct MemAlign
{
    int a;
    char b[3]; 
    int c; 
}MemAlign;

以上这个结构体占用内存多少空间呢?也许你会说,这个简单,计算每个类型的大小,将它们相加就行了,以32为平台为例,int类型占4字节,char占用1字节,所以:4 + 3 + 4 = 11,那么这个结构体一共占用11字节空间。

你可以验证一下,结果可能不是上面那样。在继续说明之前,我们必须要承认的是上述想法在没有其他限制的情况下是合理的,但是现实往往是有很多限制的。为什么呢?什么导致的呢?

why

其实这是由于计算机CPU在执行机器代码的时候,读取存在内存中的指令的时候是以一定单位进行读取的,也就是说,一次读取数据的的大小是一定的,而不是没有规则的随随便便读。早期汇编16bit单片机的时候,每次读取16bit,因为每条汇编指令是16bit。后来随着CPU和汇编的进一步发展,开始出现32位CPU、64位CPU,但是早期,最早期是有一些比较简单的计算单元或者单片机,他们是8bit、16bit的。

不同硬件平台对存储空间的处理是不同的。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如某些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据,这样数据读取效率就会很差。

由于以上的这种限制,我们为了提高程序的读取指令或者数据的速率,提高软件性能,就有了内存对齐、补齐的优化。

how

内存字节对齐是GCC编译器对C语言进行的扩展。在缺省情况下,C编译器为每一个变量或是数据单元按其自然边界对齐条件分配空间。同时GCC编译器规定了两种内存字节对齐的方法:

#pragma pack(n) //n的取值可以为1、2、4、8,在编译过程中按照n个字节对齐

#pragma pack() //取消指定对齐,按照编译器的优化对齐方式对齐

GCC编译器不建议使用#pragma进行内存字节对齐,而且#pragma最多只能支持8字节的对齐。如果n大于8则编译器会报警告,编译器将会按8字节对齐。

warning: alignment must be a small power of two, not 9 [-Wpragmas]

最后

我觉得单纯的软件开发,了解到这里应该已经足够了。

但是如果你是做驱动开发的,或者有更高的要求,你可以查看下面的链接

关于内存对齐补齐说的比较透彻的一篇博客

https://blog.51cto.com/9291927/1790295

版权声明:除特别注明外,本站所有文章均为王晨曦个人站点原创

转载请注明:出处来自王晨曦个人站点 » 关于C语言中的对齐补齐

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注