add linux kernel min, max define:
include/linux/kernel.h
/*
* min()/max() macros that also do
* strict type-checking.. See the
* "unnecessary" pointer comparison.
*/
#define min(x,y) /
(__extension__/
({ /
typeof(x) _x = (x); /
typeof(y) _y = (y); /
(void) (&_x == &_y); /
_x < _y ? _x : _y; }) /
)
#define max(x,y) /
(__extension__/
({ /
typeof(x) _x = (x); /
typeof(y) _y = (y); /
(void) (&_x == &_y); /
_x > _y ? _x : _y; }) /
)
如上是include/linux/kernel.h中关于min和max两个很常用的宏的定义,在其中我们可以看到以下几个关键点:
1. 为何不用更简单的(x>y)?x:y 这样的方式来定义,而要重新赋值一次。
2. 为何要用({ })这样的结构包围代码块
3. 那个__extension__是什么东东? (有的版本没有这个__extension__)
4. (void)(&_x == &_y)有什么用,不是脱了裤子放屁么
解答:
1. 如果用户使用了min(x++,y++)会有怎样的结果?
所以最好的办法是避免在宏的实体里让参数出现一次以上。老的linux用的是 x>?y,这个>?操作符是返回x和y中较大的一个,不过GCC的文档里已经决定抛弃这种老的用法了。
2. GCC的扩展里像{ }这种结构也是可以有值的,其值就是其中最后一个语句的值(包括左值),这里外面再加个括号是为了保险,比如:
printf("猜猜会显示什么?/n答案是:%d/n",({
int i = 0;
int j = 999;
int x = (i++) + j;
})
);
最后的输出会是:
猜猜会显示什么?
答案是:1000
3. __extension__:
GCC引入了很多标准C中的没有的扩展,如({和)},GCC提供了pednatic选项用于检测程序是否使用了GCC的扩展,当使用pedantic选项编译如下程序时:
int i;
typeof(i) j;
这个"typeof"是在GCC的内核里实现的,是GCC的扩展,在其他编译器下无法使用,所以如果编译时增加了-pedantic选项,这里就会报告WARN。
但是呢,现在用__extension__宏将其wrap起来以后,即使使用了-pedantic选项,也不会报告WARN了。
(不过我个人不太认可这种方式,这种方式隐藏了移植中的问题,但是反过来一想,换一个平台编译,那个平台的min和max宏肯定不会使用typeof,所以也许这个写法还是没问题的)
4.(void)(&_x == &_y)
(void) (&_x == &_y)这句话本身都执行程序来讲完全是一句废话,它的作用在于,本身我们无法做这样的操作typeof(_x)==typeof(_y),所以故意判断他们2个的地址指针是否相等,显然是不可能相等,但是如果_x和_y的类型不一样,其指针类型也会不一样,2个不一样的指针类型进行比较操作,会抛出一个编译警告。也就是说char *p; int *q; 然后p==q;,这个判断因为一个是char*一个是int*,会在编译时产生一个warning。巧妙就巧妙在这里。
由于内核是很多开发着一起开发的,其中还有一些其他的实现,就跟我们平常用的一样:
#define min(a,b) (((a) < (b)) ? (a) : (b))
试想:
min(++a,++b) ==> ((++a)<(++b))?(++a):(++b)
是不是就有问题了,传入的参数被加了两次。