在GCC的文档中建议使用如下的min宏定义:
引用:#define min(X,Y) \
(__extension__ \
({ \
typeof(X) __x=(X), __y=(Y); \
(__x<__y)?__x:__y; \
}) \
)
本文讨论了这样作法的意义。
1、传统的min带来的副作用
2、GCC中的({statement list})的扩展
3、typeof(expression)
4、__extension__的含义
5、使用typeof和({})实现min,避免了副作用
附录1、旧版本的的GCC中的的解决方法
附录2、C++中使用template的解决方法
1、传统的min带来的副作用
min通常被定义成这样的宏:
#define min(X,Y) ((X) < (Y) ? (X) : (Y))
这种定义会带来一些副作用,看下面的例子:
int x = 1, y = 2;
int main()
{
printf("min=%d\n", min(x++, y++));
printf("x = %d, y = %d\n", x, y);
}
执行完min(x++、y++),我们期望x的值为2,y的值为3。
但是,实际的结果是,执行完mini(x++、y++)后,x的值为3,y的值为3,原因在于宏展开后x++被执行了两次:
引用:
int x = 1, y = 2;
int main()
{
printf("min=%d\n", x++ < y++ ? x++ : y++);
printf("x = %d, y = %d\n", x, y);
}
2、GCC中的({statement list})的扩展
({statement list})是一个表达式,逗号表达式类似,但是功能更强,({与})中可以包含有多条语句(可以是变量定义、复杂的控制语句),该表达式的值为statement list中最后一条语句的值,举例:
int main()
{
int result = ({
int i, sum = 0;
for (i = 1; i <= 100; i++)
sum+= i;
sum;
})
printf("result=%d\n", result);
}
运行结果:
result=5050
3、typeof(expression)
typeof(expression)用来获取expression的类型,举例:
int main()
{
int integer;
typeof(100) i; /* 表达式100的类型是int,定义了int型变量i */
typeof(integer) j; /* 表达式integer的类型是int,定义了int型变量j */
i = 1;
j = 2;
}
4、__extension__的含义
GCC引入了很多标准C中的没有的扩展,如({和)},GCC提供了pednatic选项用于检测程序是否使用了GCC的扩展,当使用pedantic选项编译如下程序时
int main()
{
int result = ({
int i, sum = 0;
for (i = 1; i <= 100; i++)
sum+= i;
sum;
})
printf("result=%d\n", result);
}
编译器发出警告:
$ cc -pedantic test.c
test.c: 在函数 ‘main’ 中:
test.c:9: 警告:ISO C 不允许在表达式中使用花括号组
编译器提醒程序员,这段C程序使用了不符合ISO C标准的语法,如果使用其他的编译器(非GCC)编译这段代码有能会出错。在所有使用GNU 扩展关键字的表达式之前加__extension__ 关键字后,使用pedantic选项编译时,编译器就不再发出警告信息:
int main()
{
int result = __extension__({
int i, sum = 0;
for (i = 1; i <= 100; i++)
sum+= i;
sum;
})
printf("result=%d\n", result);
}
$ cc -pedantic test.c
$ 编译成功!
5、使用typeof和({})实现min,避免了副作用
#define min(X,Y) \
({ \
typeof(X) __x=(X), __y=(Y); \
(__x<__y)?__x:__y; \
})
使用传统的min会出现问题的例子:
int x = 1, y = 2;;
int main()
{
printf("min=%d\n", min(x++, y++));
printf("x = %d, y = %d\n", x, y);
}
它被扩展为
引用:
int x = 1, y = 2;;
int main()
{
printf("min=%d\n", ({
typeof(x) __x = (x++), __y = (y++); /* 定义了两个整形变量 */
(__x<__y)?__x:__y;
})
);
printf("x = %d, y = %d\n", x, y);
}
在执行min(x++, y++)期间,x++和y++只执行了一次,因而结果是正确的。
附录1、旧版本的的GCC中的的解决方法
旧版本的GCC提供了两个内置的运算操作符:<?和>?, <?返回两个操作数中较小的一个,>?返回两个操作数中较大的一个,使用这两个操作符定义的min如下:
#define min(x, y) ((x) <? (y))
#define max(x, y) ((x) >? (y))
但是新版本的GCC文档中宣称:现在这两个运算操作符已经过时了,建议大家不要使用。
附录2、C++中使用template的解决方法
template <class type>
type min(type a, type b)
{
return a < b ? a : b;
}
来源: http://www.chinaunix.net/jh/23/934870.html
add
linux
kernel min, max define:
include/
linux
/kernel.h
/*
* min()/max() 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; })
#define max(x,y) ({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x > _y ? _x : _y; })
相关推荐
漫画赏析:Linux 内核到底长啥样?漫画赏析:Linux 内核到底长啥样?漫画赏析:Linux 内核到底长啥样?漫画赏析:Linux 内核到底长啥样?漫画赏析:Linux 内核到底长啥样?
电子科技大学研究生课程课件:LINUX内核技术 教材:robert Love 著。 易于自学,方便老师教学。
从 2.4 到 2.6:Linux 内核可装载模块机制.
基础实验:linux内核的编译与内核模块.doc
linux内核中的min、max函数1
鉴于此,《Linux内核精髓:精通Linux内核必会的75个绝技》选取了资源管理(CPU、内存、进程等)、文件系统、网络、虚拟化、省电、调试、概要分析、追踪、内核调整等Linux内核的核心主题进行了深入剖析和讲解,总结出...
《Linux内核精髓:精通Linux内核必会的75个绝技》 《Linux内核精髓:精通Linux内核必会的75个绝技》 《Linux内核精髓:精通Linux内核必会的75个绝技》
电子科技大学研究生课程课件:LINUX内核技术 教材:robert Love 著。 易于自学,也方便老师教学。
编写本书是为了向学生和专业人员提供在Linux内核中实现网络功能时所需的基础知识,本书也适合所有希望深入理解操作系统内部网络特定进程的人。本书介绍了Linux内核的关键网络组件及机制,同时也介绍了通信系统的设计...
Linux驱动第二弹:Linux内核模块.pdf
详细描述了linux2.4/2.6内核版本中的网络子系统。解释了协议的工作方式、建立了Linux网络体系结构中的多种重要概念——从设备驱动程序概念一直到应用程序接口的概念。能帮助读者更容易理解 Linux网络架构的进程和...
Linux网络体系结构:Linux内核中网络协议的设计与实现.chm english
CVE-2020-14386:Linux内核权限提升漏洞分析 APT 安全研究 安全 漏洞分析 应急响应
从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响
理解Linux内核最好预备的知识点:懂C语言懂一点操作系统的知识熟悉少量相关算法懂计算机体系结构Linux内核的特点:结合了unix操作系统的一些基础概念Linux内核的任务:1.从技术层面讲,内核是硬件与软
推荐linux资料,linux内核图解。
一本很好的linux内核入门书籍,内容详尽,理解方便。
在2013中国Linux内核开发者大会上,来自Oracle的Linux内核开发者刘勃介绍了内核中的内存压缩技术。通过内存压缩,可以在进行页面回收时,无需频繁的磁盘读写操作。