use a macro within a macro

I want to write a macro that computes the volume of a sphere.

Attempt 1: I get "Pi" is undefined.


1
2
3
4
5
6
7
8
9
10
11
12
13

#include <cmath>  
# include <iostream>
# include <math.h>
#define volume(r)  (4.0/3)*Pi*pow(r,3)

int main()
{

 volume(1);

}
 



Atttempt 2: I get operand of * must be a pointer.what does that mean ?


1
2
3
4
5
6
7
8
9
10
11
12
13
14

#include <cmath>  
# include <iostream>
# include <math.h>
#define Pi 3.14 ; 
#define volume(r)  (4.0/3)*Pi*pow(r,3)

int main()
{

 volume(1);

}
 



Why do you want to write a macro? Why not a function?
See: ES.31: Don't use macros for constants or "functions"
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Res-macros2
for practice purpose
Remove the semicolon at the end of your definition of Pi

Put a std::cout << before volume(1)

When you have got it to work, follow @keskiverto and @JLBorges' advice.
does n't "Pi" come from cmath or some library , so why do I need to define it ?
It's not in the standard, so you need to provide it (unless your compiler gives you it as an extension). It was, however, what was causing your error message at the second attempt.

You don't need #define Pi 3.14 (and that's not very accurate anyway). Just replace with
const double Pi = 3.14159265358979;
http://www.piday.org/million/

To get as close to the real value of π as possible I would use at least one more digit.

 
const double Pi = 3.141592653589793;

It doesn't hurt using many more digits just to be on the safe side.
Last edited on
windows calculator gives a decent # of digits
3.1415926535897932384626433832795
which I think exceeds a normal double's capacity. This is probably the 80 bit floating point value, if you want to go that far with it.

pow for small integer powers is also clunky. Better to just say r*r*r

also, its <cmath> for c++, math.h is a C header.

macros can do a small # of things you can't do anywhere else, eg microsoft at least provides some debug macros like "what function am I in right now" and so on. For the most part, macros are best avoided as error prone and difficult to debug; they can also cause type safety problems.
Last edited on
pow for small integer powers is also clunky. Better to just say r*r*r

But the argument might not be an integer.

More importantly, if you must write a macro, always always ALWAYS enclose the definition in parentheses and enclose any use of the argument in parentheses too:

Bad:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <cmath>
#include <iostream>
#define Pi 3.141592653589793
#define volume(r)  (4.0/3)*Pi*r*r*r

using std::cout;

int
main()
{
    cout << "volume(1) = " << volume(1) << '\n';
    cout << "1 / volume(1) = " << 1 / volume(1) << '\n';
    cout << "volume(1+1) = " << volume(1+1) << '\n';
    cout << "volume(2) = " << volume(2) << '\n';
}

volume(1) = 4.18879
1 / volume(1) = 2.35619
volume(1+1) = 7.18879
volume(2) = 33.5103


Good:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <cmath>
#include <iostream>
#define Pi 3.141592653589793
#define volume(r)  ((4.0/3)*Pi*(r)*(r)*(r))

using std::cout;

int
main()
{

    cout << "volume(1) = " << volume(1) << '\n';
    cout << "1 / volume(1) = " << 1 / volume(1) << '\n';
    cout << "volume(1+1) = " << volume(1+1) << '\n';
    cout << "volume(2) = " << volume(2) << '\n';
}

volume(1) = 4.18879
1 / volume(1) = 0.238732
volume(1+1) = 33.5103
volume(2) = 33.5103

Is the concern here that r might be an expression with side effects, such as a function call?

Edit:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <cmath>
#include <iostream>
#define Pi 3.141592653589793
#define volume(r)  ((4.0/3)*Pi*(r)*(r)*(r))

using std::cout;
using std::cin;

double getRadiusFromUser()
{
	cout << "What is the sphere radius? ";
	double radius;
	cin >> radius;
	return radius;
}

int main()
{
    cout << "The sphere volume is " << volume(getRadiusFromUser()) << ".\n";
}

What is the sphere radius? 3
What is the sphere radius? 1
What is the sphere radius? 2
The sphere volume is 25.1327.

^ One of many reasons to prefer functions.
Last edited on
pow does too much work, its relatively slow because its doing a convoluted process for potentially fractional *powers* (the base does not matter). When the power is an integer, like the very common squares and cubes in so many formulae, it is usually better to just multiply it yourself. If you need to compute r to the 3.76th power, use pow. If you need r cubed, cube it yourself. I think pow can also generate minor rounding problems in a few cases.

There is nothing 'wrong' with what you did, just something to be aware of as pow can become an annoying time-waster deep in math code inner loops, and it exposes another issue with macros, performance tuning is hard when you can't see the function doing the slowness because its masked...
Last edited on
it exposes another issue with macros, performance tuning is hard when you can't see the function doing the slowness because its masked

Isn't the same true for functions?
> Better to just say r*r*r

Definitely not inside the definition of a macro.


> Is the concern here that r might be an expression with side effects, such as a function call?

That is one of the concerns.
The use of unparenthesised macro arguments as part of a bigger expression can lead to general insanity even when there are no side effects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <cmath>
#include <iostream>

#define PP_MATH_PI double(3.1415926535897932384626433)

#define PP_VOLUME_BAD(r)  (4.0/3) * PP_MATH_PI * std::pow( (r), 3.0 )
#define PP_VOLUME_WORSE(r) ( (4.0/3) * PP_MATH_PI * (r) * (r) * (r) )
#define PP_VOLUME_WORST(r) ( (4.0/3) * PP_MATH_PI * r*r*r )

int main()
{
    int i ;

    // bad because it is a macro
    i = 5 ;
    std::cout << PP_VOLUME_BAD( --i ) << '\n'  ;

    // worse because it engenders undefined/unspecified behaviour (macro argument has side effects)
    // the saving grace is that atleat in in this case, the programmer would know that there
    // is a serious problem (UB); the compiler can and would generate a warning
    i = 5 ;
    std::cout << PP_VOLUME_WORSE( --i ) << '\n' ;

    // worst because it gives absurd (unintuitive, unintended) results (even though there are no side effects);
    // and the compiler is helpless: it can't warn us (it hasn't even seen the macro).
    i = 3 ;
    std::cout << PP_VOLUME_WORST( i+1 ) << '\n' ;
}
masterinex wrote:
for practice purpose

Ok. What are you actually practicing?
Isn't the same true for functions?

No, the function calls are picked up by your performance tuner by name.
the macros are expanded so it tells you that pow is the problem, but finding where it was called might be a challenge. Could be some profilers are smarter now, but last one I used could not name the macro behind the issue.

Topic archived. No new replies allowed.