宏扩展如何在下面的代码中工作?

时间:2016-07-24 06:35:22

标签: c

在下面的代码中,根据我的说法,输出应为11 6 10,但它会给出12 6 11。自k=x x>yx=10以及y=6i=11和{{1}以来由三位运算符返回的j=6的值那么为什么产生的输出不匹配?

k=10

2 个答案:

答案 0 :(得分:2)

扩展相当于:

k = (i++) > (++j) ? (i++) : (++j);

评估条件时,ij都会增加(因此i变为11j变为6。条件检查i的原始值和j10 > 6的递增值,i++后的?k被分配11i增加到12。

因此输出应该是:

12 6 11

这里没有未定义的行为。在评估条件后,有一个完整的序列点。

另请注意,为了完全安全,宏应该在扩展周围有一组额外的括号:

#define MAX(x,y)  ((x) > (y) ? (x) : (y))

否则,你会得到奇数球效果:

int l = 7 * MAX(k, i) + 3;

有效;它只是没有按预期工作。

答案 1 :(得分:1)

输出按预期工作。您需要了解宏的扩展,并且不像复制输入参数的函数那样工作。

上述代码中MAX的定义是

let pickedDate: Date = sender.date
let NumOfDays: Int = daysBetweenDates(startDate: pickedDate, endDate: Date())
    print("Num of Days: \(NumOfDays)")

所以

#define MAX(x, y) (x)>(y)?(x):(y)

扩展为

k = MAX(i++, ++j)

当i = 10且j = 5时,变量i增加两次。变量j只增加一次。

因此最终i = 12且j = 6,并且k = 11,因为三元运算符中的第二个操作数是后增量。

如果您使用的是gcc,那么在.c文件中运行 cpp 而不是 gcc 会很好地扩展宏。

除了Jonathan Leffler关于在宏中使用更多括号来表示安全性的评论之外,您可以考虑使用内联函数来避免这些意外结果。内联函数具有键入,按值传递和代码扩展的优点。

k = (i++)>(++j)?(i++):(++j)

有关详细信息,请参阅wiki