对min(a,b)这个宏的讨论(转)

转自:http://bbs.chinaunix.net/viewthread.php?tid=934870

 

在GCC的文档中建议使用如下的min宏定义:


QUOTE:
#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通常被定义成这样的宏:

  1. #define min(X,Y) ((X) < (Y) ? (X) : (Y))
复制代码


这种定义会带来一些副作用,看下面的例子:

  1. int x = 1, y = 2;
  2. int main()
  3. {
  4.    printf("min=%d/n", min(x++, y++));
  5.    printf("x = %d, y = %d/n", x, y);
  6. }
复制代码


执行完min(x++、y++),我们期望x的值为2,y的值为3。

但是,实际的结果是,执行完mini(x++、y++)后,x的值为3,y的值为3,原因在于宏展开后x++被执行了两次

QUOTE:
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中最后一条语句的值,举例:

  1. int main()
  2. {
  3.     int result = ({
  4.      int i, sum = 0;
  5.      for (i = 1; i <= 100; i++)
  6.           sum+= i;
  7.      sum;
  8.     })
  9.     printf("result=%d/n", result);
  10. }
  11. 运行结果:
  12. result=5050
复制代码



3、typeof(expression)
typeof(expression)用来获取expression的类型,举例:

  1. int main()
  2. {
  3.    int integer;
  4.    typeof(100) i;  /* 表达式100的类型是int,定义了int型变量i */
  5.    typeof(integer) j; /* 表达式integer的类型是int,定义了int型变量j */
  6.    
  7.    i = 1;
  8.    j = 2;
  9. }
复制代码



4、__extension__的含义
GCC引入了很多标准C中的没有的扩展,如({和)},GCC提供了pednatic选项用于检测程序是否使用了GCC的扩展,当使用pedantic选项编译如下程序时

  1. int main()
  2. {
  3.     int result = ({
  4.      int i, sum = 0;
  5.      for (i = 1; i <= 100; i++)
  6.           sum+= i;
  7.      sum;
  8.     })
  9.     printf("result=%d/n", result);
  10. }
复制代码


编译器发出警告:

  1. $ cc -pedantic test.c
  2. test.c: 在函数 ‘main’ 中:
  3. test.c:9: 警告:ISO C 不允许在表达式中使用花括号组
复制代码


编译器提醒程序员,这段C程序使用了不符合ISO C标准的语法,如果使用其他的编译器(非GCC)编译这段代码有能会出错。在所有使用GNU 扩展关键字的表达式之前加__extension__ 关键字后,使用pedantic选项编译时,编译器就不再发出警告信息:

  1. int main()
  2. {
  3.     int result = __extension__({
  4.     int i, sum = 0;
  5.      for (i = 1; i <= 100; i++)
  6.           sum+= i;
  7.      sum;
  8.     })
  9.     printf("result=%d/n", result);
  10. }
  11. $ cc -pedantic test.c
  12. $ 编译成功!
复制代码



5、使用typeof和({})实现min,避免了副作用

  1. #define min(X,Y) /
  2. ({  /
  3. typeof(X) __x=(X), __y=(Y);  /
  4. (__x<__y)?__x:__y;  /
  5. })
复制代码


使用传统的min会出现问题的例子:

  1. int x = 1, y = 2;;
  2. int main()
  3. {
  4.    printf("min=%d/n", min(x++, y++));
  5.    printf("x = %d, y = %d/n", x, y);
  6. }
复制代码


它被扩展为

QUOTE:
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如下:

  1. #define min(x, y) ((x) <? (y))
  2. #define max(x, y) ((x) >? (y))
复制代码


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

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值