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宏定义相关推荐

  1. Linux内核源码中使用宏定义的若干技巧

    在C中,宏定义的概念虽然简单,但是真要用好却并不那么容易,下面从Linux源码中抽取一些宏定义的使用方法,希望能从中得到点启发: 1. 类型检查 比如module_init的宏定义: 点击(此处)折叠 ...

  2. Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 【转】...

    原文地址:Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinauni ...

  3. Linux内核源码分析方法

    说明:这是一个刚接触内核三个月的同学,通过对一个内核特性的分析,总结出一套分析内核的方法. 一.内核源码之我见 Linux内核代码的庞大令不少人"望而生畏",也正因为如此,使得人们 ...

  4. HotSpot源码(一):Docker与虚拟机的区别,class字节码解析,linux内核源码下载地址,Yacc与Lex快速入门

    Docker是虚拟机吗? Docker是用来隔离的,使用的是隔离的namespace,使用OS提供的接口进行应用程序之间的资源隔离,不是虚拟机.再加上它自己特殊的文件系统,一层一层叠加.他只不过是一个 ...

  5. linux内核开发基础(linux内核源码、树莓派源码编译、SD卡挂载)

    首先下载树莓派linux内核源码: 下载网址:https://github.com/raspberrypi/linux 在树莓派使用指令:uname -r查看当前树莓派的版本号,然后选择对应的linu ...

  6. 【华为云技术分享】Linux内核源码结构(1)

    在上一期中,我们介绍了Linux内核发展的历史,也介绍了与其相关的UNIX和GNU的相关知识.从这一期开始,我们将介绍Linux内核的源码结构.我们将先根据Linux源码的目录结构进行分析,到本文章发 ...

  7. linux的进程/线程/协程系列3:查看linux内核源码——vim+ctags/find+grep

    linux的进程/线程/协程系列3:查看linux内核源码--vim+ctags/find+grep 前言 摘要: 1. 下载linux内核源码 2. 打标签方法:vim+ctags 2.1 安装vi ...

  8. ARM树莓派高级开发——linux内核源码、树莓派源码编译、SD卡挂载

    文章目录 linux内核开发基础(linux内核源码.树莓派源码编译.SD卡挂载) 树莓派等芯片带操作系统的启动过程 linux内核源码树 Linux内核源代码目录树结构: 树莓派Linux源码配置 ...

  9. 详细讲解Linux内核源码内存管理(值得收藏)

    Linux的内存管理是一个非常复杂的过程,主要分成两个大的部分:内核的内存管理和进程虚拟内存.内核的内存管理是Linux内存管理的核心,所以我们先对内核的内存管理进行简介. 一.物理内存模型 物理内存 ...

最新文章

  1. SAP MM MIGO界面‘Where’标签页里的storage bin
  2. vssver2.scc 文件是干啥的?
  3. Objective-C语言中对象相等性与指针相等分析。
  4. 牛客 - 导航系统(最小生成树+Floyd)
  5. [BZOJ2326] [HNOI2011] 数学作业 (矩阵乘法)
  6. 模拟模型学习 几何布朗运动_Java的几何布朗运动
  7. 网页 php pdf文件怎么打开是乱码,打开php文件乱码的解决方法
  8. python与机器学习(七)下——torchvision预训练模型测试真实图像分类
  9. [转载] pandas入门
  10. 新塘linux启动过程,NUC972调试笔记之NAND分区调整新增
  11. lnmp 一键安装后 MySQL密码
  12. 线光谱共焦传感器—专注于3D视觉检测
  13. pentaho java代码_将Pentaho移植到Eclipse_ee里运行
  14. 函数:给小学生出加法运算题,判断对错并统计得分
  15. 自考学习记录 课程代码03708《中国近代史纲要》1
  16. matplotlib+basemap画出标记地图
  17. Web of Science 数据库导出记录中各个字段的含义
  18. 别再无脑get、set了,快使用lombok,从此不用再get、set
  19. 20岁后长高增高秘诀
  20. 关于windows下安装wampserver服务器系统丢失msvcr100.dll及VCRUNTIME140.dll的解决办法

热门文章

  1. 电脑安装软件出现更改计算机怎么回事,win10电脑总是自动安装软件怎么办
  2. python批量检索文献_自从用了Python,轻松查文献,释放80%的重复劳动时间!
  3. 判断是否是数组的方法
  4. oracle带输出参数存储,oracle带输入输出参数存储过程(包括sql分页功能)
  5. Java黑皮书课后题第9章:9.7(Account类)设计一个名为Account的类,它包含……。编写一个测试程序,创建一个账户ID为1122、余额为20000美元、年利率为4.5%的Account…
  6. C语言学习之输入任意年份,判断是否为闰年
  7. 获取界面url_PHP调用百度地图接口,根据IP地址获取地区
  8. java web中align命令_java web开发
  9. 课时5:闲聊之Python的数据类型
  10. php$_GET 变量