为什么以下函数被调用三次

我曾尝试调试,但没有运气我无法理解为什么第二个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 

此序列根据您的输出。

需要注意的是,您可能使用不同的编译器进行不同的输出,因为函数参数的评估顺序未定义为未定义的行为。

http://www.stroustrup.com/bs_faq2.html#macro

这是宏中副作用的典型示例。 你的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()进行一次评估的测试被执行以产生结果。