过了很久,现在突然想起了一道网易TTT计划中的一道笔试题,是关于宏定义的,但是对于宏定义很不了解,现在记录一下,大概整理一下思路,不知道对不对,希望大家勿喷。
具体的题目记不大清楚了,大概是根据以下两种宏定义的表达,问在程序编译和运行时,可能会出现什么不同的结果。
第一种宏定义表达:
#define max( a, b ) ( a > b ) ? a : b
第二种宏定义的表达:
#define max( a, b ) ({ int A = a ; int B = b ;( A > B ) ? A : B;})
笔试结束之后,我大概的查阅了一些资料,大概知道了一下。以下的内容有的是借鉴别人的分析,
一:第一种形式的分析
对于第一种表达,表面上看上去不会有什么不妥,但是在实际的程序调用中就会出现bug,看下面的例子(例1):
int a = 3; int b = 4; int c = 2 * max( a++, b++); //本来程序想要的结果是 c = 2 * 5;即c = 10; //但是实际的结果是: c = 12;
为什么呢?
根据宏定义的执行过程,我们知道,在程序编译时,编译器自动将使用了宏定义的地方进行展开,对于普通的宏定义即例如(例2):
#define PI 3.1415926
程序编译过程中只是简单的查找和替换,所以,将使用了PI的地方全部替换成3.1415926是不会出现意想不到的错误的。虽然例2的编译过程也是替换,下面来看一下,具体的替换过程:
int c = 2 * max( a++, b++); //=> c = 2 * (a++ > b++ ? a++ :b++ )
想必大家看到这里就应该明白了,为什么结果是12而不是10了吧,原因很简单,宏定义进行替换的时候,是将所有的参数一起替换,不是将参数的运算的结果计算出来之后再做相应的替换的。
对于上面的错误,在编译器的第三版本可以使用
#define max(a,b) ( (a) > (b) ? (a) : (b) )
来规避错误,但是当程序中使用下面的例子的时候,意想不到的事情又会不期而至
int c = 2 * max (3 , 4 > 5 ? 4 : 5)
以下进行展开:
int c = 2 * (max(3,4 > 5 ? 4 : 5)); //=> c = 2 * (3 > 4 > 5 ? 4 : 5 ? 3 :4 > 5 ? 4 : 5) //=> c = 2 * ((3 > (4 > 5 ? 4 : 5 )? 3 :4) > 5 ? 4 : 5) //=> c = 2 * ((3 > 5 ? 3 : 4) > 5 ? 5 : 4) //=> c = 2 * (4 > 5 ? 5 :4) //=> c = 2 * 4 //=> c = 8
这种情况又怎样解决呢?
第二种的分析,请看下一篇博文:宏定义续