15 September 2014

如果让你写一个求最小值的宏定义时,大部分人可能觉得很简单,心想只要注意加上括号不久可以么,信手拈来,刷刷写下:

#define min(x, y) ((x) < (y) ? (x) : (y))

确实在大部分情况下,这个宏定义已经足够使用,我们考虑这么一种情况:

int a = 3;

int b = 4;

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

printf("a = %d,b = %d", a, b);

代码中将将a++和b++作为参数传入,本是先比较a和b,然后将a和b加1,运行这段代码会发现首先输出最小值4,然后a等于5,b等于5。问题就出在++运算符上。min(x++,y++)被替换为((a++) < (b++) ? (a++) : (b++)),首先执行(a++) < (b++)语句,比较a和b,比较完成之后两者都加1,然后输出时因为输出的是a,此时返回的值是a++,于是先返回4之后,a又加1。

那我们如何避免这种情况呢?我们可以用两个值来保存两个参数,然后使用两个参数进行计算,那这两个参数的类型我们如何得知呢?可以通过typeof关键字,这个关键字是GNU 扩展的C语言关键字,VC不支持。我们看下代码:

#define min(x, y) ({ \

typeof(x) _min1 = (x); \

typeof(y) _min2 = (y); \

_min1 < _min2 ? _min1 : _min2; })

注意在这些复合语句外面套了两层括号:{}和():

使用{}将宏里面多个语句包裹起来,也就是所谓的局部程序块,可以让这个局部程序全部执行完,假如没有了这个{},在一些语句中就会出现歧义,比如if(a) min(x,y),这样就会出问题,条件为真时,只会执行typeof(x) _min1 = (x);这一条语句,后面的语句就不会执行了。

使用()是因为()里面加上复合语句是GCC扩展中的一个用法,在GCC扩展中允许把一个()内的复合语句看成是一个表达式,称为语句表达式,它可以出现在任何语句表达式可以出现的地方。比如当我们写return min(x,y);时,会将这些复合语句看成一个表达式,不然的话编译会报错。而且当你的宏定义需要返回值时,使用小括号()把复合语句括起来使得该复合语句最后一条语句的运算结果作为该宏的返回值。

使用了两个变量来保存传入的参数,这样似乎达到了我们的目的。可是如果我们传入的参数类型不一样呢?宏定义的一个缺点就是不会进行类型检查,我们如何能够实现参数类型的检验呢?有同学可能会说直接比较typeof(a)和typeof(b)是否相等好了,可是事与愿违,使用typeof()判断类型相等时会报错。我们可以使用&_min1 == &_min2来判断,判断&_min1和&_min2是否相等,就是判断x和y的指针是否相等。在判断两个变量是否相等的时候,编译器会先判断两个变量的类型是否相等。如果x和y的类型不等,编译的时候会报错。

&_min1 == &_min2比较的结果我们并没有使用,如果编译选项中有-Wunused-value选项(GCC警告选项,用来警告一个显式计算表达式的结果未被使用)时,编译会产生警告,我们可以通过在&_min1 == &_min2前面加上void来将两个地址比较后的比较结果强行扔掉,此时编译选项中有-Wunused-value选项就不会有警告了,此时代码变为:

#define min(x, y) ({ \

typeof(x) _min1 = (x); \

typeof(y) _min2 = (y); \

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

_min1 < _min2 ? _min1 : _min2; })

此时,我们的代码应该就没什么问题了,其实上面这段代码是Linux内核源码中求最小值的宏定义,短短几行代码却暗藏许多机巧,也显示了牛人们扎实的基本功,还是继续敲代码好好学习吧!

求最小值C语言用宏定义,最小值宏定义的解析相关推荐

  1. 求数组中数的最大值、最小值(C语言)

    求数组中数的最大值.最小值(C语言) #include<stdio.h>void main(void) {int num[10],i,imax,imin,imaxp,iminp;for(i ...

  2. c语言fmin最小公倍数,已知函式f(x)=2分之1cos的平方x加2分之根号3sinxcosx加1,X属于R 。求在[π/12,π/4]上的最大最小值...

    已知函式f(x)=2分之1cos的平方x加2分之根号3sinxcosx加1,X属于R .求在[π/12,π/4]上的最大最小值以下文字资料是由(历史新知网www.lishixinzhi.com)小编为 ...

  3. C语言之一些值得被定义为常用C语言头文件库的漂亮宏定义

    原文连接:https://mp.weixin.qq.com/s/OICAfQgMKWfBLuZbp2gCBw 写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性等等. ...

  4. C语言宏定义、宏函数、内置宏与常用宏

    前言: 在C语言中,变量类型.循环控制.基础语法等与其他高级语言基本无异:而C语言(C++)特有的两把双刃剑指针和宏定义/宏函数使得C语言在底层开发中披荆斩棘.无所不能.这两个概念涉及范围比较广,其分 ...

  5. 最小值c语言编写自定义函数,C语言笔记55:自定义函数[老九学堂]

    函数定义 return_type function_name ([datetype1 arg1],[datype2 arg2,[...]){ //函数体 } 函数三要素返回值类型 函数名 参数列表 书 ...

  6. C语言1115数组最小值,C语言数组[共52页]

    <C语言数组[共52页]>由会员分享,可在线阅读,更多相关<C语言数组[共52页](52页珍藏版)>请在人人文库网上搜索. 1.第8周实验,作业1: 从键盘输入20个数到m数组 ...

  7. 编写一个头文件,头文件中定义一个宏cube(x)用于求一个数的平方

    <程序设计基础实训指导教程-c语言> ISBN 978-7-03-032846-5 p145 7.1.2 上级实训内容 [实现内容17]编写一个头文件,头文件中定义一个宏cube(x)用于 ...

  8. C语言有符号整数最小值,16位带符号整数为什么是

    公告: 为响应国家净网行动,部分内容已经删除,感谢读者理解. 话题:16位带符号整数为什么是回答:剩下15位二进制数的最大值是每一位数都是1的情况,即2^15-1=326.326化成二进制为1000 ...

  9. 6 获取数组中最小值_C语言每日一练8——数组中最大值和最小值

    题目: 利用指针函数,求某数组中的最大值和最小值. 实现代码: /* ================================================================= ...

  10. 6-4 求一组数中的最大值、最小值和平均值

    6-4 求一组数中的最大值.最小值和平均值 编写函数,求一组数中的最大值.最小值和平均值. 函数接口定义: float fun(int a[],int n,int *max,int *min); 其中 ...

最新文章

  1. 影著协公布的使用费收取标准
  2. 低速自动驾驶车辆的定位与建图
  3. Git提交到多个远程仓库(多看两个文档)
  4. N的阶乘末尾有多少个0
  5. sql server 2008学习9 视图
  6. python1~10阶乘while_Python3基础 while 阶乘
  7. 使用某个文件夹下的所有文件去替换另一个文件夹下及其子文件夹下存在的同名文件(Python实现)...
  8. Linux作者批评英特尔指令集,英特尔回应 Linus Torvalds 对 AVX512 的批评
  9. 基于JAVA+SpringMVC+Mybatis+MYSQL的实体店会员服务系统
  10. java 数据类型转换的一场_Java数据类型之间的转换
  11. 正则表达式中符号的含义(可能不是很全)
  12. HTML创建几个边框,使用HTML5创建多个边框
  13. javaweb JAVA JSP眼镜销售系统购物系统jsp购物系统购物商城系统源码(jsp电子商务系统)网上眼镜在线销售
  14. 智能客服问题相似度算法设计——第三届魔镜杯大赛第12名解决方案
  15. SQL Server_SQL Server Windows NT - 64 bit
  16. python根据坐标画点并标记_python-如何使用colormap为matplotlib散点图中的特定点设置标记类型...
  17. Windows下的U盘监控
  18. 树莓派上编译安装hostapd
  19. Filter Listener
  20. 临床试验中edc录入_临床试验中使用EDC的情况?

热门文章

  1. Windows 底下安装 git Server: Bonobo Git Server
  2. 免编程让你零基础制作App
  3. 利用Python进行数据分析之金融数据的统计分析
  4. PS新手教程:加深减淡工具使用方法
  5. Mysql出现问题:ERROR 1819 (HY000): Your password does not satisfy the current policy requirements解决方案
  6. UVA 11549 模拟 Floyed判圈法的应用 Calculator Conundrum
  7. 科普|未来 3~5 年内,哪个方向的机器学习人才最紧缺?
  8. jmeter分布式执行远程机报错,提示“Engine is busy – please try later”
  9. A段架构设计_隽语集(IT+設計思考_1801)
  10. 做SEO优化必须掌握的10大技能