研究SGI STL的stl_clloc.h源代码中读到如下一段代码, 其中ROUND_UP()的作用是将非8倍数的整数上调到8的倍数。
其实现代码非常简单只有一行
(((bytes) +__ALIGN-1) & ~(__ALIGN - 1))
由于本人数学不是很好, 特将其实现原理及理解思路作简单解释, 方便自己以后理解及其它有需要的读者。
// instead of enum { x = N }, but fewcompilers accept the former.
# ifndef__SUNPRO_CC
enum {__ALIGN = 8};
enum {__MAX_BYTES = 128};
enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
# endif
static size_t ROUND_UP(size_t bytes) {
return (((bytes) + __ALIGN-1) &~(__ALIGN - 1));
}
如果对位运算不清楚的读者,建议可以先看看这篇文章:
C++位运算:http://www.cnblogs.com/flying_bat/archive/2008/06/17/1224178.html
正文:
阅读了上述网页文章,自己再动手在纸上展开画一下, 就会发现round_up的实现(数学)原理(以进制思维来理解)其实很简单和自然:
具体讲解如下:
1. round_up函式:
enum {__ALIGN = 8};
static size_t ROUND_UP(size_t bytes) {
return (((bytes) + __ALIGN-1) &~(__ALIGN - 1));
2. C++ (~)符号的作用是对位取反 即 0001 0001 取反后为 1110 1110
3. round_up实现原理:
以 bytes = 30为例:
a. (30 + 7) = 37, 可以知道30的round_up为32, 给32加(8-1)的目的是让其(一定)大于32
b. 这样的话,以十进制形式,37肯定可以表达为如下的形式:(x*8 + y), 并且可以肯定这个y的值小于8,上述37表达形式为:(32 + 5)
c. 根据上述b步骤的形式,我们很自然的明白, 只要将 ((bytes) + 8-1) 转换为(x*8 + y)的形式后,然后再将y的值减去就达到目的了
d. 总结上述思路,我们要做事情有两个,一是将 ((bytes) + 8-1) 转换为 (x*8 + y)的形式; 二是将(x*8 + y)中的y值清零
e. 在十进制下,要完成上述任务,比较困难,而在二进制下,就非常好办
f. 首先,将 ((bytes) + 8-1) 转换为(x*8 + y), 只要将 ((bytes) + 8-1)的值转为二进制,如以37为例,其二进制为: 00100101,这样写你可能看得还不是很直观,这样写 (00100) (101), 这样就可以发现,第一个小括号里面的值就为(x*8), 第二个小括号里面的值就为(y);
接下来,我们的目的就很简单的, 将第二个小括号里面的所有位置为0即可, 参考上述网页中的规则“非运算和与运算结合,可以确保将指定位 清0, 故 & ~(__ALIGN - 1)的目的就是将第二个小括号中的位清0.
至此, 问题圆满解决。