龙空技术网

C编程技巧——向上或向下对齐的方法及原理

日增月累 208

前言:

现在看官们对“c语言输出左右对齐”大体比较关注,我们都需要学习一些“c语言输出左右对齐”的相关资讯。那么小编也在网上搜集了一些对于“c语言输出左右对齐””的相关资讯,希望姐妹们能喜欢,我们快快来了解一下吧!

在编程中经常使用字节对齐来管理分配的内存,需要字节对齐的根本原因在于CPU访问数据的效率和存储空间的使用率问题。例如,一个处理器一次总是从存储器中取出4个字节的数据。如果所有的int类型(这里默认int类型占4个字节)数据的地址对齐成4的倍数,那么就可以用一个操作来读或写int型的数据了。否则,我们可能需要执行多次操作来实现一个int型数据的访问,因为数据可能被分放在几个4字节的存储块中,这样效率会明显降低很多。

总体而言,字节对齐满足如下简单规律(其余的以此类推):

2字节对齐:要求地址为2, 4, 6, 8…,二进制地址的最后一位为0(2的1次方)

4字节对齐:要求地址为4,8,12,16…,二进制地址的最后两位为0(2的2次方)

上述是字节对齐的简单描述,相信有过C编程经验的同学肯定是一看就明白了。有时候在编程时,要动态分配内存了,为了能充分利用内存空间和数据安全,总是会要求把分配的内存按一定的要求向上或向下对齐,那么这时候该怎么操作呢?

首先看两个宏定义(取自RT-Thread源码)

向上对齐:

#define RT_ALIGN(size, align)           (((size) + (align) - 1) & ~((align) - 1))

向下对齐:

#define RT_ALIGN_DOWN(size, align)      ((size) & ~((align) - 1))

向上或向下对齐,换个通俗的描述就是

向上对齐:计算size以align为倍数的上界数(15以8为倍数的上界数:16)

向下对齐:计算size以align为倍数的下界数(15以8为倍数的下界数:8)

以上描述,相信大家一看就明白了,那么怎么通过编码实现呢?还是以一个实例来看

向下对齐

例:计算size以align字节向下对齐(int类型,这里定义占4个字节)

int size = 15;int align = 8;

以二进制理解其原理,其实开篇就给出了答案:

8字节对齐:要求地址为8,16,24,32…,二进制地址的最后三位为0,即:align = 8;

size对齐后二进制后三位为:000

xxxxxxxx xxxxxxxx xxxxxxxx xxxxx000

size要得到以上数,是不是与运算下面这个数呢

11111111 11111111 11111111 11111000

上面二进制数就是~((align) - 1),该数可以称其为对齐字节的掩码

那么size的运算如下:

size二进制表示:

00000000 00000000 00000000 00001111

按8字节对齐后为

00000000 00000000 00000000 00001000

即:size为8

那么整个运算过程就是下面这个式子,这样就得到了向下对齐的数

((size) & ~((align) - 1))

向上对齐

同理,要向上对齐,用的对齐字节的掩码还是一样:~((align) - 1),只需把size向上扩展一个(align-1)即可,即加上(align-1)

(((size) + (align) - 1) & ~((align) - 1))

这里可以理解下,加align-1是为了向上补齐,找出上界,看是否满align个字节

这里有的同学可能要问了,怎么不是加align,而是align-1呢?

还是举个例子:align = 8

如size=16,8字节对齐的上界数就是16,此时加上align-1是23,运算后还是16,解释如下:

16原本就是8的倍数,余数为0,向上扩展align-1个字节后,不满一个align大小,所以对齐后还是16,如果是向上扩展align,就直接加了一个align大小,显然不对

如size=18,8字节对齐的上界数为24,此时加上align-1是25,运算后还是24,解释如下:

18不是8的倍数,8字节对齐后,还余2个字节,要求是向上对齐,那么就需要把这2个字节凑个8字节,这时候加align-1,就变成9个字节,满足一个align大小,所以运算的结果就是24

不是加align,而是align-1,显然明白了吧,就是一个数学问题,与求商和余数是一个道理。

标签: #c语言输出左右对齐