nginx中宏定义ngx_align(d, a)

nginx中的pool用到了这玩意:

#define ngx_align(d, a)     (((d) + (a - 1)) & ~(a - 1))

其实这篇大部分不是解释这玩意啥用的...简单一句话就是得到一个a的倍数c,且这个倍数是d的最小弱上界,得到这个值啥好处,实际上就是得到一个pool的最小size罢了,尽量减少内存的使用。

一开始我一脸懵逼,后面搜了下这个表达式发现有人在百度知道上回答了,仔细看了下他的其实不太对,后面自己就在百度知道上添加了一些补充,现在发到博客上吧:

上面的zjuzzh317大佬回答的很好了,但还是想补充下....

设f(a,b) = (a+b-1)&~(b-1),f(11,6) = 16,此时16 并不能整除6,但是b为2的幂时上式是确实可行的。可以参照下面代码跑一下。那么如何证明这个结论呢,首先b如果是2的幂此时b-1应该按2进制如下排列,这里设a>0,b>1。

b-1 b

1    10

11  100

111 1000

1111 10000

...

~将其取反则此时非0位全部为1,则&的意思很明确了,就是在高位上取一些左值对应位也为1的。设c = a+b-1,c>a,c&~(b-1)是如何保证其值是b的倍数呢,

按照我们上面的分析,b在二进制中只有一位为1,我们设这个位置是p,则b=2的p-1次方,OK,那么~(b-1)保证了这些可取的高位一定是b的倍数,如111 1000,

~111实际上是11111...000,如果你熟悉二进制,那么很显然前面那些1,我只要取一个就肯定是1000的倍数了。OK,那么我们如何保证c&~(b-1),一定会有一个1取到呢?也很容易分析:

先写下隐藏条件:c>a,c>b。

c>b,意味着存在比p要高或者相同的位中有一个为1。以上说明了f的值是b的倍数。那么如何保证f的值是a的上界,且是最小的?想想看还有哪个式子没用到?显然是c>a,c>a这个式子意味

着什么呢?实际上和上面哪个思想类似,因为c>a,而且c&~(b-1),这个~(b-1)左边所有的位都是1,那么我们把a+b-1分成两种情况:第一种,在第p位中有进位的情况(说明下第p位进位是什么

意思,省的产生误会,我这里假设进位的意思是两个数二进制下相加,第p位往上进1,则wo们称第p位有进位)此时说明了什么?

是不是在p位或者p+1...p+2..这些位上进位了?OK,进位不就意味着c&~(b-1)>a了吗。在第p位没产生进位,这是什么情况呢?实际上,b-1,中p以下的低位是不是都是1呢,如果不进位,肯定意味

着a在p以下的低位根本没有1,而此时我们用c&~(b-1)就等于a。这样,就证明了c&~(b-1)一定是a的弱上界,即f > a,上面我们还能得到f<=c,这里为啥写出来呢?下面要用到哈哈,

f<=c,实际上也很容易看出来,只需要考虑第一种情况,进位时,可能存在c中有比第p位的更低位为1,而&使得c中的这些位置为0了,其余位自然不变,因此f<=c。

现在我们只差最后一步了,即是证明f的值一定是a的最小弱上界,这里弱的意思就是说这个值可以是a。显然我们只需要考虑第p位存在进位的情况,假设我们存在一个更小的下界d,d是b的倍数,

且d<f,那么我们应该要找到一个k>0,使得d = f - k,这时f-k在二进制下会发生什么情况呢,因为f是b的倍数,所以p位以下必全0,所以k的p位以下也一定要是一个全0的情况,否则这会使得f-k

不是b的倍数。但是k>0,那么k必定要有在p位或p位以上的某些位为1,这不就说明k >= b了吗,这里我们就可以想到前提条件d >= a了,如果d >= a则f-k >= a,即f >= a + k,即

f >= a + b,这与f<=c矛盾了,因此并不存在一个更小弱上界了。

综上,f(a,b)是b的倍数,且f(a,b)是a的一个最小弱上界。

这里还遗留一个问题,也就是我们最开始说到的,b为什么一定要是2的幂?如果不是2的幂,则b-1,无法产生p位以下全1的情况,~(b-1)也无法产生p位以上全1的情况,此时上面的证明失效。例如f(25,6) = 26。

整这个玩意整了1个多小时,都忘记源码看哪来了。

#include <unistd.h>
#include <stdio.h>
void fun(int a,int b){
    printf("%d\n",(a+b-1)&~(b-1));
}
int main(){
    int a,b;
    while(~scanf("%d%d",&a,&b)){
        fun(a,b);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/zhuiyicc/p/11787631.html

时间: 2024-10-12 03:45:53

nginx中宏定义ngx_align(d, a)的相关文章

C语言中宏定义(#define)时do{}while(0)的价值(转)

C语言中宏定义(#define)时do{}while(0)的价值 最近在新公司的代码中发现到处用到do{...}while(0),google了一下,发现Stack Overflow上早有很多讨论,总结了一下讨论,加上自己的理解,do{...}while(0)的价值主要体现在: 1. 增加代码的适应性 下面的宏定义没有使用do{...}while(0) #define FOO(x) foo(x); bar(x); 这样宏定义,单独调用不会出现问题,例如: FOO(100) 宏扩展后变成: 1 f

ATL中宏定义offsetofclass的使用

近日学习ATL,通过对宏定义offsetofclass的解惑过程,顺便分析下虚函数表,以及通过虚函数表调用函数的问题. 1 解开ATL中宏定义offsetofclass的疑惑 #define _ATL_PACKING  8 #define offsetofclass(base, derived) ((unsigned long)(static_cast <base*>((derived*)_ATL_PACKING))-_ATL_PACKING) 分析如下:(base 基类 , derived

ATL中宏定义offsetofclass的分析

近日学习ATL,通过对宏定义offsetofclass的解惑过程.顺便分析下虚函数表,以及通过虚函数表调用函数的问题. 1 解开ATL中宏定义offsetofclass的疑惑 #define _ATL_PACKING  8 #define offsetofclass(base, derived) ((unsigned long)(static_cast <base*>((derived*)_ATL_PACKING))-_ATL_PACKING) 分析例如以下:(base 基类 , derive

C语言中宏定义使用方法详解

C语言中的宏替换详解 首先看一个问题: #include <stdio.h> #define    PRINT_CLINE()    printf("%d", ______) int main(void) { PRINT_CLINE(); PRINT_CLINE(); return 0; } 在横线处填上适当的代码,使得上面这段代码的输出为34. 我想一般人看到这个问题的时候头脑里都没有明确的思路来解答这个它.我看到这个问题的时候想出了各种办法来解答它,最终还是没有通过编译

C语言中宏定义之 ## 用于可变参数

GCC 支持复杂的宏,它使用一种不同的语法,使你可以给可变参数一个名字,如同其它参数一样,比如: 引用 #define debug(format, args...) fprintf(stderr, format, args) 这种定义可读性更强,也更容易描述.完整测试代码: 引用 #include <stdio.h> #define debug(format, args...) fprintf(stderr, format, args) int main(){    char a[20] = 

c语言中宏定义#和 ##的作用:

转载:http://www.cnblogs.com/cyttina/archive/2013/05/11/3072969.html 看了这篇文章后了解了,但是文章中的例子比较特别,我在这里加个注释好了. http://www.cnblogs.com/welkinwalker/archive/2012/03/30/2424844.html 单井号就是将后面的 宏参数 进行字符串操作,就是将后面的参数用双引号引起来 双井号就是用于连接. 比如文章中的例子: #define PRINT(NAME) p

解决C++中宏定义导致的名字污染

在编写一个 Graph 模板类的时候,为了使用户可以自定义 距离 的类型,比如 int 或者 double 甚至其他高精度有理数的封装类, 我将距离的类型定义为模板参数 T_DIST ,并使用了标准库中的库函数 std::numeric_limits<T_DIST>::max() 来定义最大距离 template <typename T_DIST> const typename TopologicalGraph<T_DIST>::Distance Topological

iOS开发分分钟搞定C语言 —— 宏定义和关键字

一.宏定义 概念:宏定义实质是一个预编译指令,在程序未运行之前将某些指令付给相应的变量.一般情况预处理指令都是以#号开头的,所以宏定义也是以#开发,关键字为#define(定义宏定义),#undef(结束宏定义). 定义格式及作用域 一般宏定义都定义在程序的首段: #define 宏名 值. 宏定义的作用域:从开始定义的那行起,一直到文件末尾,虽然默认情况下宏定义的作用域是从定义的那一行开始, 一直到文件末尾.但是我们也可以通过对应的关键字#under提前结束宏定义的作用域. 宏定义规范 一般情

[转载]c语言宏定义

一. #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能理解该命令的本质,总是在此处产生一些困惑,在编程时误用该命令,使得程序的运行与预期的目的不一致,或者在读别人写的程序时,把运行结果理解错误,这对 C语言的学习很不利. 1 #define命令剖析 1.1   #define的概念 #define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为