我曾尝试调试但没有运气我无法理解为什么第二个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
答案 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.
答案 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)
在这个陈述中,如果b代表一个函数,如果(a> b)为真,则只调用一次,如果(a> b)为假则调用两次:一个给出比较参数( b在“(a)&gt;(b)”)中,另一个返回整个语句的值(b在宏的后半部分)。
在你的情况下,额外调用“b”(增量)以在每次测试中提供第二个整数参数。
总共两次,三次。