3

我曾尝试调试但没有运气,我不明白为什么第二个 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
4

6 回答 6

10

因为你这么说:

MAX(x, increment())

评估为

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

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

于 2013-07-29T07:59:04.707 回答
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

这个顺序是根据你的输出。

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

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

于 2013-07-29T07:59:41.817 回答
1

发生这种情况是因为您的宏将扩展为( (x) > (increment()) ? (x) : (increment()) ).

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

于 2013-07-29T08:01:27.113 回答
1

这是宏中副作用的经典示例。您的max宏示例如下:

x > increment() ? x : increment()

一旦从 increment() 的返回值如果大于x三元运算符将调用increment()两次,一次评估条件,一次评估错误部分(即第二个increment())。

在这种情况下,你最好是最大化 max_int功能:

int max_int(int a, int b)
{
  return a > b ? a : b;
}

调用它而不是MAX将确保您的参数只被评估一次。

于 2013-07-29T08:02:04.237 回答
0

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

特别是,宏扩展为

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

因此,如果条件(需要对 , 进行一次评估的测试increment()increment()被执行以产生结果。

于 2013-07-29T08:01:23.470 回答
0

( (a) > (b) ? (a) : (b) )

在此语句中,如果 b 代表一个函数,如果 (a > b) 为真,它将只调用一次,但如果 (a > b) 为假,则调用两次:一次为比较提供参数(b in "(a ) > (b)"),另一个为整个语句返回一个值(b 在宏的后半部分)。

在您的情况下,需要额外调用 "b"(increment) 以在每个测试中提供第二个整数参数。

总而言之,它的两次和三次。

于 2013-07-29T08:06:16.073 回答