下面的代码没有给出正确的输出。
#include <stdio.h>
#define PI 22/7
#define AREA(r) PI * r * r
int main() {
printf("Pi: %d\n", PI);
printf("Area: %d\n", AREA(8));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
而下面的代码给出了正确的(最接近的)输出。
#include <stdio.h>
#define PI 22/7
#define AREA(r) r * r * PI
int main() {
printf("Pi: %d\n", PI);
printf("Area: %d\n", AREA(8));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这些代码究竟有何不同?
为什么会这样呢?我无法理解上述代码给出不同答案的区别。
问题是你的PI
宏:
#define PI 22/7
Run Code Online (Sandbox Code Playgroud)
这样做有两个问题:(1)它没有用括号括起来,以防止它的某些部分与它所扩展的表达式的其他部分更紧密地结合,以及(2)它正在进行整数除法。
如果你22/7
自己有的话,那就是3
。想必这不是您想要的。但是这个AREA
宏也有问题,如下所示:
#define AREA(r) r * r * PI
Run Code Online (Sandbox Code Playgroud)
扩展后PI
,这相当于:
#define AREA(r) r * r * 22/7
Run Code Online (Sandbox Code Playgroud)
假设r
是一个简单的变量或常量,这相当于:
#define AREA(r) (r * r * 22) / 7
Run Code Online (Sandbox Code Playgroud)
如果r
是整数,仍然是整数除法,只是最后截断,所以结果会更准确。
请注意,AREA
它自己有两个问题:(1) 它没有将其参数 括r
在括号中,(2) 它没有将整个表达式括在括号中。
对于问题 (1),想象一下传递类似2+3
as的东西r
。由于乘法比加法关联得更紧密,因此这显然不会达到您想要的效果。
如果您想要准确的结果,通常会使用精确的浮点值 pi,而不是极其不准确的近似值 22/7。但如果你确实想使用 22/7,你仍然应该使用浮点值:
#define PI (22.0/7.0)
Run Code Online (Sandbox Code Playgroud)
然后你可以修复AREA
:
#define AREA(r) (PI * (r) * (r))
Run Code Online (Sandbox Code Playgroud)
This will properly protect the arguments and final results from reassociating after expansion, but note that the result will have type double
. Also note that its argument, r
, is evaluated twice.
But a better approximation to pi is preferable. On Linux, math.h
exports M_PI
, which is far more accurate.