(转载) min()的宏定义中的(void) (_x == _y)的含义
Original Address:http://www.crifan.com/2010/08/13/order_min__macro_definition_void_amp__x__amp__y_the_meaning_of/
【整理】min()的宏定义中的(void) (&_x == &_y)的含义
近日无意间发现,关于常见的min的宏定义,在Linux中是这样的:
/*
* min()/max()/clamp() macros that also do
* strict type-checking.. See the
* "unnecessary" pointer comparison.
*/
#define min(x, y) ({
typeof(x) _x = (x);
typeof(y) _y = (y);
(void) (&_x == &_y);
_x < _y ? _x : _y; })
关于其中的:
(void) (&_x == &_y);
很是疑惑,表面看起来,这句话,好像不起作用,算是一句废话,所以去找了一下别人的解释,才大概搞懂是啥意思。
首先,我们此处想要实现的目的是,在计算两个数的最小值之前,希望去判断一下两个值的类型是否一致,而由于C语言本身不支持我们去做类似于这样的操作typeof(_x)==typeof(_y),所以在此,通过故意判断他们2个的地址指针是否相等,而显然&_x,即x的地址,是不可能等于&_y的,但是这句话(void) (&_x == &_y);使得,如果_x和_y的类型不一样,其指针类型也会不一样,2个不一样的指针类型进行比较操作,则会引起编译器产生一个编译警告,提示你这两个值的类型不同。
比如,如果你编译下面这段代码:
int x = 2;
char y = 3;
int m;
m = min(x,y);
编译的时候,经过预处理后,就会有这样的判断操作:
int * == char *;
因此编译器就会提示你:
warning: comparison of distinct pointer types lacks a cast
所以,这个宏的巧妙之处就在于此。
所以,总结起来就是:
(void) (&_x == &_y); 用于判断输入的两个值的类型是否是一致的。如果不一致,那么编译器就会做出如下警告:warning: comparison of distinct pointer types lacks a cast
【提示】
1。其实关于min的宏,更好的做法是再加个const,即:
- #define min(x, y) ({
- const typeof(x) _x = (x);
- const typeof(y) _y = (y);
- (void) (&_x == &_y);
- _x < _y ? _x : _y; })
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,就可以避免此类问题了。
【引用】
1。(void) (&_x == &_y);
http://hi.baidu.com/huahua9901/blog/item/9640223f2a37773470cf6cc4.html
2。如下的宏定义中(void) (&_x == &_y);是怎么做到判断类型的?
http://linux.chinaunix.net/bbs/viewthread.php?tid=1161263
3。Linux内核中的Min和Max函数
http://www.armfans.net/thread-1527-1-1.html
如未注明转载则均为crifan原创,对于原创文章,转载请注明出处:在路上 - on the way
本文链接:【整理】min()的宏定义中的(void) (&_x == &_y)的含义
(转载) min()的宏定义中的(void) (_x == _y)的含义相关推荐
- define宏定义中的#,##,@#及\符号
define宏定义中的#,##,@#及\符号 在#define中,标准只定义了#和##两种操作.#用来把参数转换成字符串,##则用来连接两个前后两个参数,把它们变成一个字符串. 1.# (string ...
- 【C语言】Linux内核源码--min,swap宏定义
Linux3.5的部分宏定义在linux-3.5/include/linux/kernel.h的头文件中有定义 一: 最大值和最小值相关的宏 /** min()/max()/clamp() macro ...
- c语言长度宏定义运算符,C语言在宏定义中使用语句表达式和预处理器运算符
语句表达式的亮点在于定义复杂功能的宏.使用语句表达式来定义宏,不仅可以实现复杂的功能,而且还能避免宏定义带来的歧义和漏洞.下面以一个简单的最小值的宏为例子一步步说明. 1.灰常简单的么,使用条件运算符 ...
- 宏定义中的 ## ... __VA_ARGS__
宏定义中的##操作符和... and _ _VA_ARGS_ _ 1.Preprocessor Glue: The ## Operator 预处理连接符:##操作符 Like the # operat ...
- #与##在宏定义中的--宏展开
#与##在宏定义中的--宏展开 #include <stdio.h> #define f(a,b) a##b #define g(a) #a #define h(a) g(a) int m ...
- ANSI C and Microsoft C++中常用的预定义宏以及 宏定义中 # 和 ## 的区别
ANSI C and Microsoft C++中常用的预定义宏以及 宏定义中 # 和 ## 的区别 第一部分,常见的预定义宏 第二部分,# 和 ## 再宏定义中的使用说明 第三部分,类似 #prag ...
- C语言 带参数宏定义中 # 和 ## 知识点总结、代码分析
目录 一.宏定义中 "#"知识点 1.直接转换字符串,不展开. 2.转换出的结果一定是"字符串". 二.宏定义中 ## 知识点 1.应用场景 2."# ...
- 巧用c语言宏定义实现自动注释调试代码,C语言宏定义中的特殊用法
C宏定义中的特殊用法 在分析一些C源码时,经常会遇到各种宏定义操作,本文即总结一下C语言宏定义中常见的预定义宏.调试宏:宏的条件编译用法及特殊的宏关键字用法. #undef 限定宏的作用域 一般来讲宏 ...
- C语言宏定义中#号的作用
C语言宏定义中#号的作用 前言 #号的作用 前言 最近,在阅读uboot的源码过程中,发现了一段宏定义代码: #define U_BOOT_CMD_MKENT_COMPLETE(_name, _max ...
最新文章
- 【建站系列教程】1、前言
- areas where akka is being deployed into production
- 在Forge Viewer上显示自订义属性
- 为何断点不停 Application_Start()方法
- java xslt 数据转换_如何将xslt结果转换为Java对象?
- Exynos4412裸机开发——中断处理
- kafka Failed to send messages after 3 tries 问题解决
- JAVA minaio模型_分布式系统之Java IO模型
- Maven学习总结(12)——eclipse中构建多模块maven项目
- delete kubectl pod_kubectl delete
- 万年历c语言代码3000年,求万年历代码!
- word没有显示endnote_word 未显示EndNote工具条的解决方法
- 登录服务器的详细步骤
- 非容器化jenkins 连接k8s 集群
- Debian 执行apt-get update失败提示:请使用 apt-cdrom,通过它可以让 APT 识别该盘片。apt-get upgdate 不能被用来加入新的盘片
- 神起网络游戏如何推广代理?
- Android开源项目分类汇总【畜生级别】[转]
- 2021-IP地址详解02
- 前端ES5/JavaScript高频面试题 及答案
- Office共享(word,excel等)2021-09-21