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

时间:2013-07-29 07:56:31

标签: c

我曾尝试调试但没有运气我无法理解为什么第二个printf()调用increment()三次,但第一次调用的次数是预期的两倍。

#include <stdio.h>

#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

6 个答案:

答案 0 :(得分:11)

因为你这么说:

MAX(x, increment())

评估为

( (x) > (increment()) ? (x) : (increment()) )

如果条件未满足,则评估:之后的部分,从而再次调用该函数。

答案 1 :(得分:4)

因为宏:MAX(x, increment())扩展为:

( (x) > (increment()) ? (x) : (increment()) )

同样下一次宏调用扩展。

变量i是静态的,因此最初使用i = 42初始化,并且其递增的值在不同的函数调用中持续存在。

i函数返回的值为increment()的函数调用序列下面。

 increment();    i = 47, First call

   x      52       x     i       
( (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

此序列根据您的输出。

重要的是要注意,使用不同的编译器可能会有不同的输出,因为函数参数的评估顺序未定义为Undefined behavior.

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

答案 2 :(得分:1)

这是因为您的宏将展开为( (x) > (increment()) ? (x) : (increment()) )

但是,这不是唯一的问题,您的代码包含未定义的行为。参数不按指定顺序计算。

答案 3 :(得分:1)

这是宏中副作用的典型示例。您的max宏示例就是这样的:

x > increment() ? x : increment()

一旦delta()的返回值大于x,三元运算符将调用increment()两次,一次评估条件,一次评估假部分(这是第二个{{ 1}})。

在这种情况下,你最好的是最大increment()功能:

max_int

调用此而不是int max_int(int a, int b) { return a > b ? a : b; } 将确保您的参数只被评估过一次。

答案 4 :(得分:0)

使用宏非常“危险”:可能会发生各种奇怪的事情。例如,在您的情况下,如果您调用MAX( f(), g() ),则为您提供最大结果的函数将被调用两次,另一个调用仅调用一次。由于您使用MAX(x, f())f会被调用两次,当且仅当它提供的结果大于x时才会被调用。

特别是,宏扩展为

 ( (x) > (increment())? (x):(increment()) )

因此,如果条件(需要对increment()increment()进行一次评估的测试才能生成结果。

答案 5 :(得分:0)

(p)((a)&gt;(b)?(a):( b))

在这个陈述中,如果b代表一个函数,如果(a> b)为真,则只调用一次,如果(a> b)为假则调用两次:一个给出比较参数( b在“(a)&gt;(b)”)中,另一个返回整个语句的值(b在宏的后半部分)。

在你的情况下,额外调用“b”(增量)以在每次测试中提供第二个整数参数。

总共两次,三次。