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

你可能感兴趣的:(Objective-C MAX MIN 宏定义)