【C语言】Linux内核源码--min,swap宏定义
Linux3.5的部分宏定义在linux-3.5/include/linux/kernel.h的头文件中有定义
一: 最大值和最小值相关的宏
/** min()/max()/clamp() macros that also do* strict type-checking.. See the* "unnecessary" pointer comparison.*/
#define min(x, y) ({ \typeof(x) _min1 = (x); \typeof(y) _min2 = (y); \(void) (&_min1 == &_min2); \_min1 < _min2 ? _min1 : _min2; })#define max(x, y) ({ \typeof(x) _max1 = (x); \typeof(y) _max2 = (y); \(void) (&_max1 == &_max2); \_max1 > _max2 ? _max1 : _max2; })#define min3(x, y, z) ({ \typeof(x) _min1 = (x); \typeof(y) _min2 = (y); \typeof(z) _min3 = (z); \(void) (&_min1 == &_min2); \(void) (&_min1 == &_min3); \_min1 < _min2 ? (_min1 < _min3 ? _min1 : _min3) : \(_min2 < _min3 ? _min2 : _min3); })#define max3(x, y, z) ({ \typeof(x) _max1 = (x); \typeof(y) _max2 = (y); \typeof(z) _max3 = (z); \(void) (&_max1 == &_max2); \(void) (&_max1 == &_max3); \_max1 > _max2 ? (_max1 > _max3 ? _max1 : _max3) : \(_max2 > _max3 ? _max2 : _max3); })
以上几个宏会做严格的类型检查
(void) (&_min1 == &_min2);
表面看起来,这句话,好像不起作用,算是一句废话,其实作用还是比较大的。首先,我们此处想要实现的目的是,在计算两个数的最小值之前,希望去判断一下两个值的类型是否一致,而由于C语言本身不支持我们去做类似于这样的操作typeof(_x)==typeof(_y),所以在此,通过故意判断他们2个的地址指针是否相等,而显然&_x,即x的地址,是不可能等于&_y的,但是这句话(void) (&_x == &_y);使得,如果_x和_y的类型不一样,其指针类型也会不一样,2个不一样的指针类型进行比较操作,则会引起编译器产生一个编译警告,提示你这两个值的类型不同。通过void显式丢弃一个表达式的值,否则有些编译器会就此给出警告信息。
比如看看如下代码:
编译的时候,经过预处理后,就会有这样的判断操作:
int * == char *;
因此编译器就会提示你:
warning: comparison of distinct pointer types lacks a cast(警告:比较不相关的指针时缺少类型转换)
所以,这个宏的巧妙之处就在于此。
所以,总结起来就是:
【提示】
1。其实关于min的宏,更好的做法是再加个const,即:
#define min(x, y) ({ \const typeof(x) _min1 = (x); \const typeof(y) _min2 = (y); \(void) (&_min1 == &_min2); \_min1 < _min2 ? _min1 : _min2; })
2。(void) (&_x == &_y); 中的void,表示将表达式(&_x == &_y); 所得到的结果(此处肯定是逻辑上的假,值为0)忽略掉。如果不加void,则会提示你这行代码是无意义的,没人用到,有些编译器会产生警告信息。
3。关于min的宏定义,为何这么复杂,而不是用简单的#define min(x,y) ((x) < (y) ? x : y)
因为,如果如此定义,那么对于一些特殊的值传入此宏之后,就会产生一些副作用,产生的结果,就不是我们想要的了,比如:
min(++a,++b) ==> ((++a)<(++b))?(++a) : (++b)
就使得,a++和b++分别执行了2次,而且min的结果,也不对了。而用上面那个复杂的定义,多加了局部变量_x和_y,就可以避免此类问题了。
二、 其它相关宏的分析
/*** min_not_zero - return the minimum that is _not_ zero, unless both are zero* @x: value1* @y: value2*/
#define min_not_zero(x, y) ({ \typeof(x) __x = (x); \typeof(y) __y = (y); \__x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); })/** ..and if you can't take the strict* types, you can specify one yourself.** Or not use min/max/clamp at all, of course.*/
#define min_t(type, x, y) ({ \type __min1 = (x); \type __min2 = (y); \__min1 < __min2 ? __min1: __min2; })#define max_t(type, x, y) ({ \type __max1 = (x); \type __max2 = (y); \__max1 > __max2 ? __max1: __max2; })/** swap - swap value of @a and @b*/
#define swap(a, b) \do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
swap是交换两个变量的值的宏,可以支持所有的基本类型。
【C语言】Linux内核源码--min,swap宏定义相关推荐
- Linux内核源码中使用宏定义的若干技巧
在C中,宏定义的概念虽然简单,但是真要用好却并不那么容易,下面从Linux源码中抽取一些宏定义的使用方法,希望能从中得到点启发: 1. 类型检查 比如module_init的宏定义: 点击(此处)折叠 ...
- Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 【转】...
原文地址:Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinauni ...
- Linux内核源码分析方法
说明:这是一个刚接触内核三个月的同学,通过对一个内核特性的分析,总结出一套分析内核的方法. 一.内核源码之我见 Linux内核代码的庞大令不少人"望而生畏",也正因为如此,使得人们 ...
- HotSpot源码(一):Docker与虚拟机的区别,class字节码解析,linux内核源码下载地址,Yacc与Lex快速入门
Docker是虚拟机吗? Docker是用来隔离的,使用的是隔离的namespace,使用OS提供的接口进行应用程序之间的资源隔离,不是虚拟机.再加上它自己特殊的文件系统,一层一层叠加.他只不过是一个 ...
- linux内核开发基础(linux内核源码、树莓派源码编译、SD卡挂载)
首先下载树莓派linux内核源码: 下载网址:https://github.com/raspberrypi/linux 在树莓派使用指令:uname -r查看当前树莓派的版本号,然后选择对应的linu ...
- 【华为云技术分享】Linux内核源码结构(1)
在上一期中,我们介绍了Linux内核发展的历史,也介绍了与其相关的UNIX和GNU的相关知识.从这一期开始,我们将介绍Linux内核的源码结构.我们将先根据Linux源码的目录结构进行分析,到本文章发 ...
- linux的进程/线程/协程系列3:查看linux内核源码——vim+ctags/find+grep
linux的进程/线程/协程系列3:查看linux内核源码--vim+ctags/find+grep 前言 摘要: 1. 下载linux内核源码 2. 打标签方法:vim+ctags 2.1 安装vi ...
- ARM树莓派高级开发——linux内核源码、树莓派源码编译、SD卡挂载
文章目录 linux内核开发基础(linux内核源码.树莓派源码编译.SD卡挂载) 树莓派等芯片带操作系统的启动过程 linux内核源码树 Linux内核源代码目录树结构: 树莓派Linux源码配置 ...
- 详细讲解Linux内核源码内存管理(值得收藏)
Linux的内存管理是一个非常复杂的过程,主要分成两个大的部分:内核的内存管理和进程虚拟内存.内核的内存管理是Linux内存管理的核心,所以我们先对内核的内存管理进行简介. 一.物理内存模型 物理内存 ...
最新文章
- SAP MM MIGO界面‘Where’标签页里的storage bin
- vssver2.scc 文件是干啥的?
- Objective-C语言中对象相等性与指针相等分析。
- 牛客 - 导航系统(最小生成树+Floyd)
- [BZOJ2326] [HNOI2011] 数学作业 (矩阵乘法)
- 模拟模型学习 几何布朗运动_Java的几何布朗运动
- 网页 php pdf文件怎么打开是乱码,打开php文件乱码的解决方法
- python与机器学习(七)下——torchvision预训练模型测试真实图像分类
- [转载] pandas入门
- 新塘linux启动过程,NUC972调试笔记之NAND分区调整新增
- lnmp 一键安装后 MySQL密码
- 线光谱共焦传感器—专注于3D视觉检测
- pentaho java代码_将Pentaho移植到Eclipse_ee里运行
- 函数:给小学生出加法运算题,判断对错并统计得分
- 自考学习记录 课程代码03708《中国近代史纲要》1
- matplotlib+basemap画出标记地图
- Web of Science 数据库导出记录中各个字段的含义
- 别再无脑get、set了,快使用lombok,从此不用再get、set
- 20岁后长高增高秘诀
- 关于windows下安装wampserver服务器系统丢失msvcr100.dll及VCRUNTIME140.dll的解决办法
热门文章
- 电脑安装软件出现更改计算机怎么回事,win10电脑总是自动安装软件怎么办
- python批量检索文献_自从用了Python,轻松查文献,释放80%的重复劳动时间!
- 判断是否是数组的方法
- oracle带输出参数存储,oracle带输入输出参数存储过程(包括sql分页功能)
- Java黑皮书课后题第9章:9.7(Account类)设计一个名为Account的类,它包含……。编写一个测试程序,创建一个账户ID为1122、余额为20000美元、年利率为4.5%的Account…
- C语言学习之输入任意年份,判断是否为闰年
- 获取界面url_PHP调用百度地图接口,根据IP地址获取地区
- java web中align命令_java web开发
- 课时5:闲聊之Python的数据类型
- php$_GET 变量