问题
I have this simple code that converts between degrees Farehnheit and degrees Celcius. I defined some macros to do it, but I'm getting some weird results when I use it. I use this method when absoluteTemp
= 373.15 (the boiling point of water in kelvin).
#define kelvinToCelc(k) k - 273.15
#define celcToFahren(c) (9.0 / 5.0) * c + 32
double x = kelvinToCelc(absoluteTemp); // 100
double y = celcToFahren(x); // 212
double z = celcToFahren(kelvinToCelc(absoluteTemp)); // 430.52???
return celcToFaren(kelvinToCelc(absoluteTemp));
回答1:
After expanding macro in
double z = celcToFahren(kelvinToCelc(absoluteTemp));
It becomes
double z = (9.0 / 5.0) * absoluteTemp - 273.15 + 32
You need to add parentheses to the macros
#define kelvinToCelc(k) (k - 273.15)
#define celcToFahren(c) ((9.0 / 5.0) * c + 32)
回答2:
The old rule was : Use more parenthesis in macros around everything:
#define kelvinToCelc(k) ((k) - 273.15)
#define celcToFahren(c) ((9.0 / 5.0) * (c) + 32)
Notice parens around the whole macro and all macro arguments
The new rule is : Use inline functions They have typechecking, evaluate arguments only once, and because they don't need so many parenthesis *
Note: * Some exceptions may apply, this is not one of them
This is what that looks like as inline functions
inline double kelvinToCelc(double k)
{
return k - 273.15;
}
inline double kelvinToCelc(double c)
{
return (9.0 / 5.0) * c + 32;
}
Notice that you have to put inline
and the return type before the name, add types to all arguments, and add a ;
at the end
Notice how you can use newlines to make it easier to read, and also so you can step into it in the debugger
回答3:
Macros are simple - Just a text replacement
i.e.
double z = celcToFahren(kelvinToCelc(absoluteTemp));
becomes
double z = (9.0 / 5.0) * kelvinToCelc(absoluteTemp) + 32
Then becomes
double z = (9.0 / 5.0) * absoluteTemp - 273.15 + 32
Now just do the maths
i.e.
double z = (9.0 / 5.0) * 373.15 - 273.15 + 32;
回答4:
If you are going to use macros, make your life easier with parenthesis
#define kelvinToCelc(k) (k) - 273.15
#define celcToFahren(c) (9.0 / 5.0) * (c) + 32
This helps prevent the unexpected results you are seeing. The reasons have already been pointed out in other posts
回答5:
Just one thing i should add to the other answers, try running just the preprocessor and look at the output ie: g++ -E -P main.cpp
回答6:
The answer 431.52 is correct. It expanded like this
(9.0/5.0) * 373.15 - 272.15 + 32
In mathematics [* and /] take precedence over [+ and -]. So the equation expanded like
((9.0/5.0) * 373.15) - 272.15 + 32
(671.67) - 272.15 + 32
399.52 + 32
431.52
[* and /] have same precedence so there order doesn't matter and similarly [+ and -] have same precedence so their execution order doesn't matter.
回答7:
For macros, it just relies on textual substitution. So it is equivalent to:
double z = (9.0 / 5.0) * absoluteTemp - 273.15 + 32;
That's why you got wrong result.
Edit:
Try to use (inline) functions instead even you can make it work by adding more parenthesis: (see #2)
#define celcToFahren(c) ((9.0 / 5.0) * (c) + 32)
Macros are also error-prone because they rely on textual substitution and do not perform type-checking. Check out here for more info.
来源:https://stackoverflow.com/questions/21153061/c-macros-order-of-precedence-difference