1、先上实现代码:
#define __min(t1, t2, min1, min2, x, y) ({ \ t1 min1 = (x); \ t2 min2 = (y); \ (void) (&min1 == &min2); \ min1 < min2 ? min1 : min2; })#define min(x, y) \ __min(typeof(x), typeof(y), \ __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \ x, y)
__UNIQUE_ID(min1_)含义是制造一个唯一的标识符:__UNIQUE_ID_min1_0
__UNIQUE_ID(min2_)含义是制造一个唯一的标识符:__UNIQUE_ID_min2_1
2、为什么把x,y赋值给_min1和_min2然后返回_min1和_min2,而不直接写成(x) < (y)? (x) :(y)呢?这个就是最经典的C语言课本中所说的那个所谓的++的问题了,假如我写成min(a++,b++),展开成宏就变成了(a++) < (b++)? (a++) :(b++)了,究竟a和b各自++了多次,所以我们一定要先把它们赋值给两个局部变量,这样就没有这个问题了。
3、 (void) (&min1 == &min2); 这一行有啥用?检查两个数类型是否匹配,不匹配编译器会报错的,注意必须是地址之间的判等才是类型比较,如果是值的话,那就是单纯的比较数值了和类型就无关了,所以这里要转换成地址,
另外再将结果强转为void,也是加强说明这是一个类型比较,不可以用作右值,通过void显式丢弃一个表达式的值,否则有些编译器会就此给出警告信息)。(void) (&_x == &_y); 中的void,表示将表达式(&_x == &_y); 所得到的结果( 如果是逻辑上的假,值为0)忽略掉。如果不加void,则会提示你这行代码是无意义的,没人用到,有些编译器会产生警告信息。
4、为了便于研究,我把涉及到的宏全部提炼出来,写了一个测试程序:
#include#define ___PASTE(a,b) a##b#define __PASTE(a,b) ___PASTE(a,b)#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)#define __min(t1, t2, min1, min2, x, y) ({ \ t1 min1 = (x); \ t2 min2 = (y); \ (void) (&min1 == &min2); \ min1 < min2 ? min1 : min2; })#define min(x, y) \ __min(typeof(x), typeof(y), \ __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \ x, y)int main(int argc, char *argv[]){ int a=10,b=20; int c=min(a,b); printf("c=%d\n",c); return 0;}
5、__COUNTER__是GCC内置的一个累加器,每次调用都会在以前的基础上加1,从0开始计数。
6、这是解开宏后的源码:
int main(int argc, char *argv[]){ int a=10,b=20; int c=({ typeof(a) __UNIQUE_ID_min1_0 = (a); typeof(b) __UNIQUE_ID_min2_1 = (b); (void) (&__UNIQUE_ID_min1_0 == &__UNIQUE_ID_min2_1); __UNIQUE_ID_min1_0 < __UNIQUE_ID_min2_1 ? __UNIQUE_ID_min1_0 : __UNIQUE_ID_min2_1; }); printf("c=%d\n",c);