Home > Enterprise >  How does the below C macro example compile?
How does the below C macro example compile?

Time:01-18

The code below does not give the correct 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.

#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.

CodePudding user response:

The problem is your PI macro:

#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.

If you have 22/7 by itself, it's just 3. Presumably that's not what you want. But the AREA macro, which also has problems, looks like this:

#define AREA(r)  r * r * PI

With PI expanded, this is equivalent to:

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

Assuming r is a simple variable or constant, this is equivalent to:

#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.

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.

For problem (1), imagine passing something like 2 3 as 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. But if you do want to use 22/7, you should still use a floating point value for it:

#define PI (22.0/7.0)

Then you can fix 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. 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.

CodePudding user response:

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.

The second expression is 8 * 8 * 22 / 7. So the calculation is 1408 / 7 = 201.

CodePudding user response:

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), i.e 3 * 8 * 8 = 192.

The other variant gives: (((8*8)*22)/7) = (64 * 22)/7 = 1408/7 = 201.

If you want better precision, use floating point, i.e. #define PI (22.0/7.0) or, why not use a better approximation of pi: #define PI (3.141593)

But then you should use %f in printf. (as commented by Jabberwocky)

  • Related