一、问题根源
在 Linux / GCC / Clang 中:
cpp
#include <cmath>
通常就能用:
cpp
M_PI
但在 MSVC 中:
M_PI默认不定义- 需要显式开启宏,或自己定义
- 或使用 C++20 标准方案
所以才会出现:
text
error C2065: "M_PI": 未声明的标识符
二、最简单粗暴(不推荐,但常见)
在使用前手动定义:
cpp
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
能用
不优雅
易重复定义
不类型安全
三、MSVC 官方方式(老项目常用)
1.在 #include <cmath> 之前:
cpp
#define _USE_MATH_DEFINES
#include <cmath>
然后就可以:
cpp
double x = M_PI;
注意:
- 必须在
<cmath>之前 - 只对 MSVC 有意义
- 属于"平台特性"
稳定
兼容老代码
非标准 C++
四、 推荐方案
使用 C++20 std::numbers::pi
cpp
#include <numbers>
double x = std::numbers::pi;
或指定类型:
cpp
double x = std::numbers::pi_v<double>;
float y = std::numbers::pi_v<float>;
标准
类型安全
无宏
跨平台
不污染命名空间
强烈推荐
五、如果在模板 / 数值库中(非常重要)
不要在模板中用 M_PI
cpp
template<typename T>
T foo() {
return T(M_PI); // 不推荐
}
推荐:
cpp
#include <numbers>
template<typename T>
T pi() {
return std::numbers::pi_v<T>;
}
六、Eigen / GTSAM / 数值库中的惯用写法
很多数值库内部都会写:
cpp
constexpr double kPi = 3.14159265358979323846;
或:
cpp
static constexpr double pi = std::acos(-1.0);
也可以用:
cpp
constexpr double pi = std::acos(-1);
标准
无宏
编译期常量
七、工程级方案(如果不能改源码)
在 CMake 中:
cmake
add_definitions(-D_USE_MATH_DEFINES)
或:
cmake
target_compile_definitions(your_target PRIVATE _USE_MATH_DEFINES)
八、最终建议
| 场景 | 推荐 |
|---|---|
| 新项目 / 现代 C++ | std::numbers::pi |
| 旧 MSVC 项目 | _USE_MATH_DEFINES |
| 模板 / 数值库 | std::numbers::pi_v<T> |
| 快速修 bug | 手动 #define M_PI(临时) |