C++宏:优先级差异的顺序

C++ macros: order of precedence difference?

本文关键字:顺序 优先级 C++      更新时间:2023-10-16

我有一个简单的代码,可以在法伦海特度和摄氏度之间进行转换。我定义了一些宏来做到这一点,但是当我使用它时,我得到了一些奇怪的结果。当absoluteTemp = 373.15(水的沸点以开尔文为单位)时,我使用这种方法。

#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));

在 中扩展宏之后

double z = celcToFahren(kelvinToCelc(absoluteTemp));

它变成了

double z = (9.0 / 5.0) * absoluteTemp - 273.15 + 32

您需要在宏中添加括号

#define kelvinToCelc(k) (k - 273.15)
#define celcToFahren(c) ((9.0 / 5.0) * c + 32)

旧规则是: 在所有内容的宏中使用更多的括号:

#define kelvinToCelc(k) ((k) - 273.15)
#define celcToFahren(c) ((9.0 / 5.0) * (c) + 32)

注意整个宏和所有宏参数周围的括号

新规则是:使用内联函数 他们有类型检查,只计算一次参数,因为他们不需要那么多括号 *

注意:* 某些例外情况可能适用,这不是其中之一

这就是内联函数的样子

inline double kelvinToCelc(double k)
{
    return k - 273.15;
}
inline double kelvinToCelc(double c)
{
    return (9.0 / 5.0) * c + 32;
}

请注意,您必须将inline和返回类型放在名称之前,向所有参数添加类型,并在末尾添加;

请注意如何使用换行符使其更易于阅读,以及如何在调试器中单步执行换行

很简单 - 只是一个文本替换

 double z = celcToFahren(kelvinToCelc(absoluteTemp)); 

成为

 double z = (9.0 / 5.0) * kelvinToCelc(absoluteTemp) + 32

然后变成

 double z = (9.0 / 5.0) * absoluteTemp - 273.15  + 32

现在只需做数学运算

double z = (9.0 / 5.0) * 373.15 - 273.15  + 32;

如果您要使用宏,请使用括号使您的生活更轻松

#define kelvinToCelc(k) (k) - 273.15
#define celcToFahren(c) (9.0 / 5.0) * (c) + 32 

这有助于防止您看到的意外结果。 原因已经在其他帖子中指出

我应该添加到其他答案中的一件事,尝试只运行预处理器并查看输出,即: g++ -E -P main.cpp<</p>

div class="answers">

答案 431.52 是正确的。它像这样扩展

(9.0/5.0) * 373.15 - 272.15 + 32

在数学中,[* 和/] 优先于 [+ 和 -]。所以等式扩展为像

((9.0/5.0) * 373.15) - 272.15 + 32
(671.67) - 272.15 + 32
399.52 + 32
431.52
[* 和/] 具有相同的优先级,因此顺序无关紧要,

同样 [+ 和 -] 具有相同的优先级,因此它们的执行顺序无关紧要。

对于宏,它只依赖于文本替换。所以它相当于:

double z = (9.0 / 5.0) * absoluteTemp - 273.15 + 32;

这就是为什么你得到错误的结果。

编辑:

  1. 尝试使用(内联)函数,即使您可以通过添加更多括号来使其工作:(见#2)

    #define celcToFahren(c) ((9.0 / 5.0) * (c) + 32)
    
  2. 宏也容易出错,因为它们依赖于文本替换并且不执行类型检查。查看此处了解更多信息。