宏C/C++的奇怪行为
Strange behaviour of macros C/C++
本文关键字:C++ 更新时间:2023-10-16
我正在使用一些宏,并观察到一些奇怪的行为。
我将PI定义为一个常数,然后在宏中使用它将度数转换为弧度,将弧度转换为度数。度到弧度很好,但弧度到度不行:
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;
}
当我编译和运行时,我得到以下输出:
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
看起来我的常数PI在分子中起作用,但在分母中不起作用。我在C中观察到了同样的行为。我运行的是gcc版本4.6.3
有人能解释我为什么会有这种行为吗?
宏是(相对简单的)文本替换。
在定义中使用括号(同时包含宏本身和宏参数):
#define PI (atan(1) * 4)
#define radians(deg) ((deg) * PI / 180)
#define degrees(rad) ((rad) * 180 / PI)
首先,cmath
定义了M_PI
,使用它。
其次,cpp宏进行文本替换。这意味着:
#define PI atan(1) * 4
a = 1 / PI;
将变成这样:
a = 1 / atan(1) * 4;
在c/c++编译器有机会看到你的代码之前,它会把它等效为:
a = (1 / atan(1)) * 4;
这不是你想要的。
你的定义应该是这样的:
#define PI (atan(1) * 4)
一切都会好起来的。
这并不是真正奇怪的行为,而是c预处理器的行为。
你应该在网上搜索宏的其他陷阱。(提示:参数传递)
您应该为宏使用括号来指定优先级。除此之外,我认为在许多情况下,math.h将为您定义
宏只是在不考虑上下文的情况下进行文本替换,所以最终得到的是:
cout << "PI, in degrees: " << atan(1) * 4 * 180 / atan(1) * 4 << endl;
请注意,第二个atan(1) * 4
周围明显缺少parens,导致它只除以atan(1)
,然后乘以4。
相反,使用内联函数和全局变量:
const double PI = atan(1) * 4;
double radians(double deg) { return deg * PI / 180; }
double degrees(double rad) { return rad * 180 / PI; }
还有一个好的做法:在所有参数周围加括号:
#define radians(deg) ((deg) * PI / 180)
因为作为参数传递的表达式可能也包含运算符。
或者更好:使用(内联)函数而不是宏,以避免在多次评估参数时产生意外的副作用,如以下所示:
#define sqr(x) ((x) * (x))
内联函数的唯一缺点是:只能为一种类型定义它们(除非使用C++模板)
相关文章:
- 没有找到相关文章