C++ macros: order of precedence difference?

自古美人都是妖i 提交于 2021-02-11 04:36:35

问题


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:

  1. 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)
    
  2. 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!