I'm using some macros, and observing some strange behaviour.
I've defined PI as a constant, and then used it in macros to convert degrees to radians and radians to degrees. Degrees to radians works fine, but radians to degrees does not:
piTest.cpp:
#include <cmath>
#include <iostream>
using namespace std;
#define PI atan(1) * 4
#define radians(deg) deg * PI / 180
#define degrees(rad) rad * 180 / PI
int main()
{
cout << "pi: " << PI << endl;
cout << "PI, in degrees: " << degrees(PI) << endl;
cout << "45 degrees, in rad: " << radians(45) << endl;
cout << "PI * 180 / PI: " << (PI * 180 / PI) << endl;
cout << "3.14159 * 180 / 3.14159: " << (3.14159 * 180 / 3.14159) << endl;
cout << "PI * 180 / 3.14159: " << (PI * 180 / 3.14159) << endl;
cout << "3.14159 * 180 / PI: " << (3.14159 * 180 / PI) << endl;
return 0;
}
When I compile and run, I get the following output:
pi: 3.14159
PI, in degrees: 2880
45 degrees, in rad: 0.785398
PI * 180 / PI: 2880
3.14159 * 180 / 3.14159: 180
PI * 180 / 3.14159: 180
3.14159 * 180 / PI: 2880
It seems like my constant PI works in the numerator, but not the denominator. I've observed the same behaviour in C. I'm running gcc version 4.6.3
Can anyone explain why I'm getting this behaviour?
Macros are (relatively simple) textual substitutions.
Use parentheses in your definitions (both to enclose the macro itself and the macro arguments):
Macros just do text substitution without regard for context, so what you wind up with is:
Note the distinct lack of parens around the second
atan(1) * 4
, causing it to divide only byatan(1)
and then multiply by 4.Instead, use inline functions and globals:
First,
cmath
definesM_PI
, use that.Second, cpp macros do textual substitution. Which mean that this:
will be turned into this:
before the c/c++ compiler gets a chance to see your code, and it will treat it equivalent to this:
which is not what you want.
Your define should look like this:
and everything should be fine.
This is not really strange behaviour, but well documented behaviour of the c-preprocessor.
You should search the web for other pitfalls with macros. (hint: parameter passing)
You should use parenthesis for your macros to specify precedence. In addition to that, i think in many cases math.h will define PI for you
Also good practice: Add brackets around all your parameters:
because the expression you pass as parameter might include operators, too.
Or even better: Use (inline-) functions instead of macros, to avoid surprises with sideeffects when a parameter is evaluated multiple times like here:
The only disadvantage you get with inline functions: You can define them for one type, only (unless you use C++ templates)