写一个宏定义,返回两个数中较大的一个。相信绝大部分同学都能闭着眼睛写出来,但闭着眼睛写的真的对吗,怎么样写可以做到极致的优雅,适用几乎所有应用场景。
幼儿园写法:
#define MAX(a, b) a > b ? a : b
但是有些不听话的小朋友在使用这个宏的时候可能会这样写:
#include <stdio.h>
#define MAX(a, b) a > b ? a : b
int main (int argc, char *argv[])
{
printf("%d", MAX(4&4, 2&4));
return 0;
}
运行结果:
0
这就出错了,这是由于运算符优先级导致了运行结果偏离预期,&的优先级小于<。
小学写法:
#define MAX(a, b) (a) > (b) ? (a) : (b)
也有一些聪明的小学生,会写到:
#include <stdio.h>
#define MAX(a, b) (a) > (b) ? (a) : (b)
int main (int argc, char *argv[])
{
printf("%d\n", 1+MAX(3, 2));
return 0;
}
运行结果是3!这也是因为运算符优先级引发的问题,+的优先级要大于>。
初中写法:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
这样写很好地规避了运算符优先级带来的问题,但它还不是完美的,请看:
#include <stdio.h>
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int main (int argc, char *argv[])
{
int a = 3, b=4;
printf("%d\n", 1+MAX(a++, b++));
return 0;
}
运行结果是6!这是因为在比较的过程中,变量自身发生了变化,虽然编程规范一般不允许这样传递参数,但到底有没有办法规避这些隐患呢。
高中写法:
#define MAX(a, b) ({ \
int _a = a; \
int _b = b; \
_a > _b ? _a : _b; \
})
这个写法已经能规避很多问题了,但很明显的问题是,它只适用于int类型数据的比较。于是又有了
本科写法:
#define MAX(type, a, b) ({ \
type _a = a; \
type _b = b; \
_a > _b ? _a : _b; \
})
这样就可以支持多种数据类型了。但是它要用到3个“参数”,我需要比较两个数的大小,为什么要我传递3个“参数”呢。
硕士写法:
#define MAX(a, b) ({ \
typeof(a) _a = a; \
typeof(b) _b = b; \
(void)(&_a == &_b); \
_a > _b ? _a : _b; \
})
typeof在gun c上是可以支持的,它可以自动获取参数类型。
(void)(&_a == &_b);这条语句则可以用来提示传入参数类型不一致的警告。编译的时候就可以提示警告。
到这里,比较大小的宏定义已经足够优雅了。也许你会觉得写个宏定义需要这么复杂吗,别急,不妨再看看《内联函数》