什么是副作用的表达式,为什么不将它们传递给宏?

9 c macros side-effects

我在文本C如何编程中遇到了一个声明:

"不应将具有副作用的表达式(即,修改变量值)传递给宏,因为宏参数可能会被多次评估."

我的问题是什么是副作用的表达式,为什么不将它们传递给宏?

Som*_*ude 11

经典的例子是一个宏来计算两个值的最大值:

#define MAX(a, b) ((a) > (b) ? (a) : (b))
Run Code Online (Sandbox Code Playgroud)

现在让我们像这样"调用"宏:

int x = 5;
int y = 7;
int z = MAX(x++, y++);
Run Code Online (Sandbox Code Playgroud)

现在,如果MAX是一个正常的功能,我们期望xy将递增一次,对吗?但是因为它是一个宏,所以"call"被替换为:

int z = ((x++) > (y++) ? (x++) : (y++));
Run Code Online (Sandbox Code Playgroud)

如您所见,变量y将递增两次,一次在条件中,一次作为三元运算符的最终结果.

这是具有副作用(后增量表达式)和宏扩展的表达式的结果.


在相关的说明中,宏还存在其他危险.例如,让我们采用这个简单的宏:

#define MUL_BY_TWO(x)  (x * 2)
Run Code Online (Sandbox Code Playgroud)

看起来很简单吧?但是现在如果我们像这样使用它:

int result = MUL_BY_TWO(a + b);
Run Code Online (Sandbox Code Playgroud)

这将扩展为

int result = (a + b * 2);
Run Code Online (Sandbox Code Playgroud)

并且你希望知道乘法具有比加法更高的优先级,所以表达式a + b * 2相当于a + (b * 2),可能不是宏编写者想要的.这就是为什么宏的参数应该放在他们自己的括号内:

#define MUL_BY_TWO(x)  ((x) * 2)
Run Code Online (Sandbox Code Playgroud)

然后扩展将是

int result = ((a + b) * 2);
Run Code Online (Sandbox Code Playgroud)

这可能是正确的.