【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
Linux-C 最正确的取最大最小值宏
这里以两个值中取最小值为例:
#define min_t(type, x, y) \
({ type __x=x; type __y=y; __x<__y? __x:__y })
GNU C把包含在括号中的复合语句看成是一个表达式, 称为语句表达式, 它可以出现在任何允许表达式的地方. 我们可以在语句表达式中使用原本只能在复合语句中使用的循环、局部变量等, 例如:
#define min_t(type, x, y) \
({ type __x=x; type __y=y; __x<__y? __x:__y })
int ia, ib, mini;
float fa, fb, minf;
mini = min_t(int, ia, ib);
minf = min_t(float, fa, fb);
因为重新定义了__x和__y这两个局部变量, 所以用上述方式定义的宏将不会有副作用. 在标准C中, 对应的如下宏则会产生副作用:
#define min(x, y) ((x)<(y) ? (x) : (y))
在很长一段时间内我都觉得这是最正确的, 毕竟它加上了括号, 排除了x或y是一个表达式导致了错误的可能. 万万没想到当x或y是x++或者y++时它的异常情况…
代码min(++ia, ++ib)会展开为((++ia) < (++ib) ? (++ia) : (++ib)), 传入的宏的"参数"
增加了两次!
在这里我假设你在写笔试题, 然后笔试题又限制宏只能使用两个参数或者说x,y不是同一个类型的:
此时我们可以巧用typeof关键字:#define min(x, y) ({ \
const typeof(x) __x = (x); \
const typeof(y) __y = (y); \
(void) (&__x == &__y); \
__x < __y ? __x : __y; })
我们不需要像min_t(type, x, y)那个宏那样把type传入, 因为通过typeof(x)、typeof(y)可以获得type.
代码行(void)(&__x == &__y)的作用是检查__x和__y的类型是否一致.指针(地址)的比较也需要相同类型, 不同的话编译器会警告!
以上内容大部分摘抄自《Linux设备驱动开发详解 基于最新的Linux4.0内核》宋宝华
第三章 Linux内核及内核编程