为什么以下函数被调用三次
我曾尝试调试,但没有运气我无法理解为什么第二个printf()调用increment()三次,但第一个调用两次预期。
#include #define MAX(a, b) ( (a) > (b) ? (a) : (b) ) int increment(){ static int i = 42; i += 5; printf("increment returns %d\n", i); // 47, 52, 57 return i; } int main( int argc, char ** argv ) { int x = 50; // parameters compute from right to left side printf("max of %d and %d is %d\n", x, //3rd: 50 increment(), //2nd: 52 MAX(x, increment()) //1st: 50,47 -> 50 ); printf("max of %d and %d is %d\n", x, //3rd: 50 increment(), //2nd: 62 MAX(x, increment()) //1st: 50,57 -> 57 ); return 0; }
结果
increment returns 47 increment returns 52 max of 50 and 52 is 50 increment returns 57 increment returns 62 increment returns 67 max of 50 and 67 is 62
因为你告诉它:
MAX(x, increment())
评估为
( (x) > (increment()) ? (x) : (increment()) )
如果条件未满足,则评估后面的部分,从而再次调用该函数。
因为宏: MAX(x, increment())
扩展为:
( (x) > (increment()) ? (x) : (increment()) )
同样下一次宏调用扩展。
变量i
是静态的,因此最初用i = 42
初始化,并且其递增的值在不同的函数调用中持续存在。
下面是一个函数调用序列,其中的值由increment()
函数返回。
increment(); i = 47, First call x 52 xi ( (50) > (52) ? (50) : (52) ) Second // ^ not called because condition is True 50 > 52
第二次:
increment(); i = 57, Third call x i x i ( (50) > (62) ? (50) : (67) ) Forth Fifth // called because condition is False 50 > 62
此序列根据您的输出。
需要注意的是,您可能使用不同的编译器进行不同的输出,因为函数参数的评估顺序未定义为未定义的行为。
这是宏中副作用的典型示例。 你的max
宏示例:
x > increment() ? x : increment()
一旦increment()的返回值大于x
,三元运算符将调用increment()
两次,一次评估条件,一次评估假部分(这是第二个increment()
)。
在这种情况下,你最好的是max max_int
函数:
int max_int(int a, int b) { return a > b ? a : b; }
调用此而不是MAX
将确保您的参数只被评估一次。
发生这种情况是因为你的宏将扩展为( (x) > (increment()) ? (x) : (increment()) )
。
但是,这不是唯一的问题,您的代码包含未定义的行为 。 不按指定顺序评估参数。
((a)>(b)?(a):( b))
在这个陈述中,如果b代表一个函数,如果(a> b)为真,则只调用一次;如果(a> b)为假,则调用两次:一个给出比较参数(b in“(a) )>(b)“),另一个返回整个语句的值(b在宏的后半部分)。
在您的情况下,额外调用“b”(增量)以在每个测试中提供第二个整数参数。
总共两次,三次。
使用宏是非常“危险的”:可能发生各种奇怪的事情。 例如,在你的情况下,如果你调用MAX( f(), g() )
,那么给你最大结果的函数会被调用两次,另一个只调用一次。 由于使用MAX(x, f())
,当且仅当它给出大于x
的结果时, f
才会被调用两次。
特别是,宏扩大为
( (x) > (increment())? (x):(increment()) )
因此,如果条件(需要对increment()
, increment()
进行一次评估的测试被执行以产生结果。