打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
从一个简单的宏定义看linux内核的严谨,窥C语言的强大 min()
从一个简单的宏定义看linux内核的严谨,窥C语言的强大
2010-12-17 21:13

 

最近闲来无事,分析下linux kernel里面一些函数都是怎样定义使用的,它们都是怎样避免风险的,从include/linux/kernel.h中挑出一个经典的min宏进行分析一下

 

从我们最先认识的min函数开始看看,这个函数的作用就是求两个数中小一点的那个

#define min(x, y) ({                                \

typeof(x) _min1 = (x);                        \

typeof(y) _min2 = (y);                        \

(void) (&_min1 == &_min2);                \

_min1 < _min2 ? _min1 : _min2; })

 

1)首先我们可以看到这个宏的定义外面由一个({}),为什么要这样写呢?其实{}很好理解,因为我们的宏是多个语句,假如没有了这个{},在一些语句中就会出现歧义,比如 ifa minx,y),这样就会出问题,后面的语句它就不会执行了。那么这里为什么在外面还要加一个()呢,我们来看这个函数的作用,它是用来返回一个较小的数,对,是返回,一般来说对于返回值,我们怎么用?最简单的当然是return了,所以,一般来讲,我们会写return min(x,y);(当然还有很多常用的方法,比如说赋值等等,我这边的目的只是解释()呵呵~~)。这个时候你就不难理解我们为什么要加个()了吧,不过正规的来讲,这是GCC扩展中的一个用法,在GCC扩展中允许吧一个()内的复合语句看成是一个表达式,称为语句表达式,它可以出现在任何语句表达式可以出现的地方。

2)继续看这个宏,我们知道一般我们使用这个函数的时候,x,y是什么类型的并不清楚,我们是否需要所有的类型都写一个min函数呢?其实不需要,在GCC的扩展中,我们提供了一个宏,称为typeof,它可以获得相应参数的类型,这样就可以不需要因为类型而重写宏了,小方便啊。

再看这两句话:

typeof(x) _min1 = (x);                        \

typeof(y) _min2 = (y);                        \

为什么要把xy赋值给_min1_min2然后返回_min1_min2,而不直接写成(x) < (y)? (x) :(y)呢?这个就是最经典的C语言课本中所说的那个所谓的++的问题了,还需要多说吗?好吧,我说一下吧,因为我也是菜鸟,也记不清当时是在什么地方提到这个东西了,呵呵,不过印象中记得好像是这样说的:假如我写成min(a++,b++),展开成宏就变成了(a++ < (b++)? (a++) :(b++)了,究竟ab各自++了多少次,大概可以算出来吧,所以我们一定要先把它们赋值给两个局部变量,这样就没有这个问题了。

3)下面再来看一下那个(void) (&_min1 == &_min2);这句话好纠结啊,奶奶的,反正我是没看懂是什么作用,不过可以肯定的是肯定有它存在的意义,于是只好做试验了,好吧,我写写写,写了好几个代码发现两者都是一样的,怎么办呢?呵呵,google一下,终于发现有人讲这个了,说是为了在比较不同类型的时候能够打印一个警告信息。好吧,我试试看,写一个简单测试程序

#include <stdio.h>

 

#define min(x, y) ({                                \

typeof(x) _min1 = (x);                        \

typeof(y) _min2 = (y);                        \

(void) (&_min1 == &_min2);                \

_min1 < _min2 ? _min1 : _min2; })

 

main(){

unsigned long a = 4;

in b = 5;

 

printf("min is %d\n", min(a, b));

}

gcc编译了一下,果然报下面警告了:

min.c: In function ‘main’:

min.c:14: 警告:比较不相关的指针时缺少类型转换

没有这句话,就不会报这个警告,为什么会这样呢?跟阿虚讨论了下,原来,在比较地址的时候,会发现地址所存值的类型,假如不同的话就会报警告,而在直接比较值的时候,比如上面的_min1 < _min2 ?的时候,会做强制类型转换,而且不会报警告,好吧,我真的很佩服写这段代码的人,太牛了!简单的4,5行代码,竟然有这么多的东西在里面,这叫老夫如何是好啊,继续努力。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
从min&max一窥linux设计
【整理】min()的宏定义中的(void) (&_x == &_y)的含义
Linux 内核中常出现的、主要的 GCC 扩展
K&R编码规范(linux内核编码规范)
linux驱动学习笔记(linux驱动头文件说明)
Linux TCP/IP协议栈的通用编码模式
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服