Q我正在尝试定义一些简单的类似函数的宏,例如
#define square(x) x * x但它们并不总是有效。
A定义类似函数的宏时,有三个重要的规则需要记住
1 / square(n)将展开为
1 / n * n(其计算结果为(1 / n) * n),而你想要的是
1 / (n * n)(在这种情况下,问题是结合律而非优先级,但效果是相同的。)
square(n + 1)将展开为
n + 1 * n + 1但你想要的是
(n + 1) * (n + 1)
square(i++)将展开为
i++ * i++这是未定义的(参见问题 3.2)。
正确定义的square宏,为了符合上述规则 1 和 2,是
#define square(x) ((x) * (x))遵循规则 3 更难。有时,通过仔细利用的短路行为&&, ||或?:运算符(参见问题 3.6)可以安排出现多次的参数保证只被求值一次。有时,宏只是被记录为不安全,调用者必须记住不要在具有副作用的参数上使用它。其他时候,可能建议不要编写一个类似函数的宏,如果它不能被制成安全的。
(作为一种风格惯例,宏通常定义为大写或全大写名称,以便清楚地表明它们是宏。如果一个类似函数的宏真正模拟了一个函数,那么用全小写名称定义它是可以接受的,但前提是它符合上述所有三个规则。由于我们一直在讨论的平方宏不符合,所以应该将其定义为类似
#define Square(x) ((x) * (x)) /* UNSAFE */如果它要被使用的话。)
参考文献:K&R1 第 4.11 节,第 87 页
K&R2 第 4.11.2 节,第 90 页
H&S 第 3.3.6、3.3.7 节,第 49-50 页
CT&P 第 6.2 节,第 78-80 页