在C语言中使用#define进行方程式定义

3
有人能解释一下为什么这里y的值是13吗?
#include <stdio.h>
#define avg_sum(n) n * (n-1)/2
int main(){
    int y;
    int z = 9;
    y = avg_sum(z+1);
    printf("y=%i\n",y);
}

2
这就是为什么当宏参数作为算术表达式的一部分时,你总是要在它们周围加上括号,而整个宏体也要加上括号,这样934 /avg_sum(12)才会给出预期的答案。 - Jonathan Leffler
3个回答

9
avg_sum(9+1) 9+1 * (9+1-1)/2 = 9 + 9/2 = 9+ 4 = 13

宏每次都会扩展,因此9+1不同于10。使用以下的保护括号可能更好:

#define avg_sum(n) ((n) * ((n)-1)/2)

但是一个等价的函数会更好,更直观,并且只会评估参数一次。avg_sum(a++) 将会是 ((a++) * ((a++)-1)/2) 并且会使 a 增加两次,而一个函数不会有这些问题,因为所有的参数在函数调用之前都被评估。

1
静态内联函数 static inline int avg_sum(int n) { return (n * (n-1)) / 2; } 很好用,除非你使用陈旧的 C90 编译器(例如 Windows 上默认的 MSVC)。 - Jonathan Leffler
在函数版本中,我不确定您是否需要所有括号。 - Glenn Teitelbaum
我也不确定,但谨慎总比后悔好。考虑如果在乘以n之前计算(n-1)/2 会出现什么问题:假设 n == 4。那么 (n-1)/21n*14;另一方面,(4 * 3)/26。我认为括号确实很重要,如果编译器允许重新排列操作,那么这将产生影响。 - Jonathan Leffler
1
@JonathanLeffler 5 | * / % | 乘法、除法和余数 | 从左到右 不允许重新排序 - 不需要括号 - Glenn Teitelbaum

5

回答这类问题最好的方法是简单地扩展所涉及的宏:

y = avg_sum(z+1);

y = z + 1 * (z + 1 - 1) / 2

y = 9 + 1 * (9 + 1 - 1) / 2

y == 13

这就是为什么你要在宏参数周围加上括号的原因。
#define avg_sum(n) ((n) * ((n)-1)/2)

2
y = avg_sum(z+1);

扩展为z + 1 * (z+1-1)/2,但是这是错误的。请更改您的宏为

#define avg_sum(n) ((n) * ((n)-1)/2)

在使用函数宏时,一定要将参数与宏本身都用括号括起来。这是一个重要的规则。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接