Objective-C MAX MIN 宏定义

错误的 MIN MAX 宏定义

朋友面试时遇到的一个问题:

Define a standard macro MAX with 2 parameters. It returns the greater one.
(Please provide program segments)

第一反应是这样的:

#define MYMAX(A, B) (A < B ? B : A)

然而直觉告诉我问题肯定没这么简单,那么坑在哪里?答案是当你使用 ++ 操作符的时候:

float a = 2.0f;
float b = MYMAX(a++, 1.5f);
NSLog(@"a = %f, b = %f", a, b);
// a = 4.000000, b = 3.000000

调用者的预期输出应该是 a = 3.000000, b = 2.000000,而之所以会变成 a = 4.000000, b = 3.000000,是因为经过宏替换,上面的代码相当于:

float a = 2.0f;
float b = a++ < 1.5f ? 1.5f : a++;
NSLog(@"a = %f, b = %f", a, b);

可以看到,因为前面的条件为 NO,这里 a++ 相当于执行了两遍。

正确的 MIN MAX 宏定义

我们测试一下苹果提供的 MAX 方法:

float a = 2.0f;
float b = MAX(a++, 1.5f);
NSLog(@"a = %f, b = %f", a, b);
// a = 3.000000, b = 2.000000

并没有刚才那个问题。

我们来看一下它是如何定义的:

#define __NSX_PASTE__(A,B) A##B

#if !defined(MIN)
    #define __NSMIN_IMPL__(A,B,L) ({ __typeof__(A) __NSX_PASTE__(__a,L) = (A); __typeof__(B) __NSX_PASTE__(__b,L) = (B); (__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__a,L) : __NSX_PASTE__(__b,L); })
    #define MIN(A,B) __NSMIN_IMPL__(A,B,__COUNTER__)
#endif

#if !defined(MAX)
    #define __NSMAX_IMPL__(A,B,L) ({ __typeof__(A) __NSX_PASTE__(__a,L) = (A); __typeof__(B) __NSX_PASTE__(__b,L) = (B); (__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__b,L) : __NSX_PASTE__(__a,L); })
    #define MAX(A,B) __NSMAX_IMPL__(A,B,__COUNTER__)
#endif

根据宏定义,我们来替换刚才的代码:

float a = 2.0f;
float b = ({
    __typeof__(a++) __NSX_PASTE__(__a,__COUNTER__) = (a++);
    __typeof__(1.5f) __NSX_PASTE__(__b,__COUNTER__) = (1.5f);
    (__NSX_PASTE__(__a,__COUNTER__) < __NSX_PASTE__(__b,__COUNTER__)) ? __NSX_PASTE__(__b,__COUNTER__) : __NSX_PASTE__(__a,__COUNTER__);
});
NSLog(@"a = %f, b = %f", a, b);
// a = 3.000000, b = 2.000000

__COUNTER__ 是一个预定义宏,在编译过程中从 0 开始计数,每次被调用时加 1。因为唯一性,所以通常用于构造独立的变量名。(参考:GCC: Common Predefined Macros

__NSX_PASTE__ 是连接,宏定义中不能直接写 AB 来连接参数,需要写成 A##B

假设 COUNTER 的值为 0,上面的代码可以继续被替换为:

float a = 2.0f;
float b = ({
    __typeof__(a++) __a0 = (a++);
    __typeof__(1.5f) __b0 = (1.5f);
    (__a0 < __b0) ? __b0 : __a0;
});
NSLog(@"a = %f, b = %f", a, b);
// a = 3.000000, b = 2.000000

可以看到,这里 a++ 同样写了两次,但是在 __typeof__() 中的 a++ 并没有执行。我只能说:

这是编译器的特性

PS: 无论是条件运算符,还是 if 语句中的 a++,都会执行:

float a = 2.0f;
float b;
if (a++ < 1.5f) {
    b = 1.5;
} else {
    b = a++;
}
NSLog(@"a = %f, b = %f", a, b);
// a = 4.000000, b = 3.000000
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 宏定义在C系开发中可以说占有举足轻重的作用。底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可...
    你好自己阅读 4,680评论 0 5
  • http://www.open-open.com/lib/view/open1390651437117.html ...
    Xtuphe阅读 5,055评论 0 10
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,142评论 19 139
  • 走路的羡慕开车的,也有人羡慕走路的。尽管呼吸着同一片天的空气,却有着各种各样的人生。满足到不同层次的人就会有...
    研究说明书阅读 2,790评论 0 0
  • 11月15日上午,我们聆听了来自河师大教育学院李玉芳老师的讲座《漫谈班主任领导力及提升》。本次讲座,来自我们滑县的...
    你是幸运的阅读 3,919评论 0 2

友情链接更多精彩内容