在网上看到这样一道题,不是很明白原理,记录一下。
题目和答案来自这篇文章:
【C语言面试题】请使用宏定义实现字节对齐!】
请使用C语言的宏定义实现一个功能,求得某个整型数M在N字节对齐的时,它的值大小。
说明:
1.M是一个非负整数;
2.N是2的整数倍,值可能是1,2,4,8,16等等。
要求:
1.不得使用除法(/);
2.不能使用函数实现,只能用宏实现;
3.自行设计测试用例,明确得出测试用例执行成功与否。
#define GET_ALIGNED_2_POWER_NUM(num, n) (((num) + (n) - 1) & (~((n) - 1)))
题目的意思
求得某个整型数M在N字节对齐的时,它的值大小。
一开始我没懂这句话的意思,最开始我认为,一个int型,值为2,即使4字节对齐后,值不还是2吗?
但是实际上这里求的是,某个整型数M(指的是一个变量的size大小是M),按照N字节对齐后,占用的字节数。
例如一个int变量,占用4字节,
按照2字节对齐后,占用4字节‘
按照8字节对齐后,占用8字节;
按照16字节对齐后,占用16字节。
那么,答案中宏的计算,是什么意思呢
这里在重复一下参数的意思,num:需要对齐的数据的大小,n字节对齐的条件(N是2的整数倍)。
预期的对齐效果:
如果num小于n,那么最终结果就是按照n字节对齐。
例如数据大小为5字节,对齐条件是8字节,那么数据对齐后占用8字节。
如果num大于n,那么最终结果就是按照nm来进行对齐,m是使得 nm大于num的最小值。
例如数据大小为25字节,对齐条件是8字节,那么数据对齐后占用32(4 * 8)字节。
所以是不是,把num加上对齐条件n,然后把相加之和对n取余的余数舍去就行,例如 :
num==5, n==8,
5 + 8 = 13, 13 %8= 5, 输出13 - 5 = 8。
num==25, n==8,
25 + 8 = 33, 33 %8= 1, 输出33 - 1 = 32。
但是有个漏洞,如果num 和对齐条件相等呢,取余就没有余数,例如:
num==8, n==8,
8 + 8 = 16, 16 %8= 0, 输出16 - 0 = 16。(应该是8)
num==24, n==8,
24 + 8 = 32, 32 %8= 0, 输出32 - 0 = 32。(应该是24)
这里得出的值就比预期的值大了。
所以应该把num 加上 n - 1,然后把结果中,对n取余的余数舍去。例如:
num==5, n==8,
5 + (8 - 1) = 12, 12 %8= 4, 输出12 - 4 = 8。
num==25, n==8,
25 + 8 - 1 = 32, 32 %8= 0, 输出32 - 0 = 32。
如果num 小于n,那么num + n 还是2n;
如果num 大于n,那么num + n 大于2n
如果num 小于n,那么num + n - 1 还是小于2n;
如果num 大于n,那么num + n - 1,还是大于2n
所以是否进行n-1,对num == n以外的情况没有影响。
这就是上面宏做的工作:
(((num) + (n) - 1) //把num 加上 n - 1
↓
(((num) + (n) - 1) & (~((n) - 1))) // & (~((n) - 1))) 就是把小于n的部分给舍去了。