简体   繁体   English

以下 C 宏示例如何编译?

[英]How does the below C macro example compile?

The code below does not give the correct output.下面的代码没有给出正确的 output。

#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;
}

Whereas the code below gives the correct (nearest) output.而下面的代码给出了正确的(最近的)output。

#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;
}

How exactly do these code differ?这些代码究竟有何不同?

Why is it so?为什么会这样? I am not able to understand the difference between how both the above codes would give different answers.我无法理解上述两种代码如何给出不同答案之间的区别。

The problem is your PI macro:问题是您的PI宏:

#define PI 22/7

There are two problems with this: (1) It's not wrapped in parentheses, to guard it against parts of it binding more tightly to other parts of the expression in which it's expanded, and (2) It's doing integer division.这有两个问题:(1) 它没有包含在括号中,以防止它的某些部分更紧密地绑定到它展开的表达式的其他部分,以及 (2) 它正在做 integer 除法。

If you have 22/7 by itself, it's just 3 .如果你有22/7本身,它只是3 Presumably that's not what you want.大概这不是你想要的。 But the AREA macro, which also has problems, looks like this:但是同样有问题的AREA宏看起来像这样:

#define AREA(r)  r * r * PI

With PI expanded, this is equivalent to:随着PI展开,这相当于:

#define AREA(r)  r * r * 22/7

Assuming r is a simple variable or constant, this is equivalent to:假设r是一个简单的变量或常量,这相当于:

#define AREA(r)  (r * r * 22) / 7

If r is an integer, it's still doing integer division, but it's only truncating at the end, so the result will be more accurate.如果r是一个integer,它仍然在做integer除法,但它只是在最后截断,所以结果会更准确。

Note that AREA has two problems of its own: (1) It's not wrapping its argument, r , in parentheses, and (2) It's not wrapping the expression as a whole in parentheses.请注意, AREA自身有两个问题:(1) 它没有将其参数r括在括号中,以及 (2) 它没有将整个表达式括在括号中。

For problem (1), imagine passing something like 2+3 as r .对于问题 (1),想象将2+3作为r Since multiplication associates more tightly than addition, this clearly won't do what you want.由于乘法关联比加法更紧密,这显然不会做你想要的。

If you want an accurate result, you would normally use an accurate floating-point value for pi, rather than the extremely inaccurate approximation 22/7.如果您想要一个准确的结果,您通常会为 pi 使用一个准确的浮点值,而不是极其不准确的近似值 22/7。 But if you do want to use 22/7, you should still use a floating point value for it:但是如果你确实想使用 22/7,你仍然应该为它使用一个浮点值:

#define PI (22.0/7.0)

Then you can fix AREA :然后你可以修复AREA

#define AREA(r)  (PI * (r) * (r))

This will properly protect the arguments and final results from reassociating after expansion, but note that the result will have type double .这将适当地保护 arguments 和最终结果在扩展后不会重新关联,但请注意结果的类型为double Also note that its argument, r , is evaluated twice.另请注意,它的参数r被计算了两次。

But a better approximation to pi is preferable.但是更好地近似于 pi 是可取的。 On Linux, math.h exports M_PI , which is far more accurate.在 Linux 上, math.h导出M_PI ,这要准确得多。

Try expanding the macro.尝试扩展宏。 The first one is 22 / 7 * 8 * 8. All values are integers, so you get rounding errors and the calculation is basically 3 * 8 * 8 = 192.第一个是 22 / 7 * 8 * 8。所有值都是整数,所以会出现舍入误差,计算结果基本上是 3 * 8 * 8 = 192。

The second expression is 8 * 8 * 22 / 7. So the calculation is 1408 / 7 = 201.第二个表达式是 8 * 8 * 22 / 7。所以计算结果是 1408 / 7 = 201。

Multiplication and division is done from left to right.乘法和除法是从左到右进行的。 So, AREA(8) in the first example expands to 22/7 * 8 * 8 which is evaluated like so: (((22/7) * 8) * 8), ie 3 * 8 * 8 = 192.因此,第一个示例中的 AREA(8) 扩展为 22/7 * 8 * 8,其计算方式如下:(((22/7) * 8) * 8),即 3 * 8 * 8 = 192。

The other variant gives: (((8*8)*22)/7) = (64 * 22)/7 = 1408/7 = 201.另一个变体给出:(((8*8)*22)/7) = (64 * 22)/7 = 1408/7 = 201。

If you want better precision, use floating point, ie #define PI (22.0/7.0) or, why not use a better approximation of pi: #define PI (3.141593)如果您想要更高的精度,请使用浮点数,即 #define PI (22.0/7.0) 或者,为什么不使用更好的 pi 近似值:#define PI (3.141593)

But then you should use %f in printf. (as commented by Jabberwocky)但是你应该在 printf 中使用 %f。(正如 Jabberwocky 评论的那样)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM