Chinaunix首页 | 论坛 | 博客
  • 博客访问: 411588
  • 博文数量: 96
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 415
  • 用 户 组: 普通用户
  • 注册时间: 2015-05-22 09:08
个人简介

最近的研究方向:Nginx

文章分类
文章存档

2017年(2)

2016年(59)

2015年(35)

我的朋友

分类: C/C++

2015-09-08 12:41:03

最近在看u-boot代码中看到了这段代码:
/*
 * General Purpose Utilities
 */
#define min(X, Y) \
({ typeof (X) __x = (X), __y = (Y); \
(__x < __y) ? __x : __y; })


#define max(X, Y) \
({ typeof (X) __x = (X), __y = (Y); \
(__x > __y) ? __x : __y; })

刚开始一看不是很理解这个宏定义为什么要这么写,但是知道是用来实现min(a,b)和max(a,b)这两个函数的,随即就去问候了度娘。
真是不看不知道,一看吓一跳啊~
以下是借鉴原文出处: /> 在GCC的文档中建议使用如下的min宏定义:
引用:#define min(X,Y)  \
(__extension__  \
({  \
   typeof(X) __x=(X), __y=(Y);   \
   (__x<__y)?__x:__y;  \
}) \



本文讨论了这样作法的意义。


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提供了两个[color=red]内置[/color]的运算操作符:?, ?返回两个操作数中较大的一个,使用这两个操作符定义的min如下:
#define min(x, y) ((x) ? (y))

但是新版本的GCC文档中宣称:现在这两个运算操作符已经过时了,建议大家不要使用。

附录2、C++中使用template的解决方法
template 
type min(type a, type b)
{
     return a < b ? a : b;
}

原来我们习以为常的宏定义#define min(a,b) ((a) < (b)? (a):(b))  原来有这么大的缺陷!!!
虽来此写此文,以备以后查看之用。


阅读(1570) | 评论(0) | 转发(0) |
0

上一篇:GNU ARM 汇编

下一篇:大端模式&小端模式

给主人留下些什么吧!~~