__vasz宏引发的探究

首次编辑:24/5/19/18:38
最后编辑:24/5/19/19:06

引子

在研究C语言可变参数函数的实现时,看到了这样一个宏:

#define __vasz(x)	((sizeof(x)+sizeof(int)-1) & ~(sizeof(int) -1))

让人匪夷所思。
这里的x的“实参”是一个类型关键字,返回一个大于sizeof(x)且能被sizeof(x)整除的数。
据说是为了实现内存对齐,所有数据都从4的整数倍内存地址开始存。

所以为什么这个宏是这么写的呢?

分析

先看看式子中恒定的后半部分~(sizeof(int) -1)sizeof(int)一般是4(字节),4减1为3,再按位取反,得到0xff...ffc。看十六进制或许还不太清楚,我们再把它写成2进制:

0b11...1100

再看看式子中前面的部分,用极值分析一下,sizeof(x)至少为1,1加4减掉1,也就是式子的前半部分最小为4,写成2进制为:

0b00...0100  式子的前半部分
0b11...1100  式子的后半部分

可以看到前半部分最小的情况下,2进制的第3位也与后半部分同为1,再按位与,至少也能够得到4。事实上无论x是其它任何数据类型,2进制的第3位都是1。因为sizeof(x) - 1最小为0,而又加上了sizeof(int),所以整个前半部分最小值为sizeof(int)(一般为4)。写成2进制数,第3位就是1。

而后半部分的低两位为0,无论前半部分的值是多少,和后半部分按位与之后,低两位都会是0。
而前半部分的第3位始终为1,后半部分的第3位同样也始终为1,所以相与之后,至少都能得到4。

不知道谁想出的这个宏,还挺牛逼的。

评论