M_PI在Math Studio中与math.h一起使用,但不适用于cmath


94

我正在使用Visual Studio2010。我已经读过在C ++中使用<cmath>而不是更好<math.h>

但是在程序中,我尝试编写以下内容(Win32控制台应用程序,空项目):

#define _USE_MATH_DEFINES
#include <math.h>

它会编译,而如果我写

#define _USE_MATH_DEFINES
#include <cmath>

它失败了

错误C2065:“ M_PI”:未声明的标识符

正常吗 我使用cmath还是math.h是否重要?如果是,我如何使其与cmath一起使用?

更新:如果我在GUI中定义_USE_MATH_DEFINES,它可以工作。任何线索为什么会这样?


您的源文件是.c还是.cpp?
瑞士人

1
瑞士人:在这里没关系。
rubenvb 2011年

非常奇怪...我可以确定我在VS2010中遇到了同样的问题...正在研究阻止定义通过的原因...必须在某处未定义...但是我不知道在哪里
Goz

使用x86,它将报告错误C2065。使用x64,则没有错误。
user2616989

Answers:


116

有趣的是,我在我的一个应用程序上检查了此错误,并得到了相同的错误。

我花了一段时间检查标题,以查看是否有任何无法解决的问题_USE_MATH_DEFINES,但没有发现任何问题。

所以我搬了

#define _USE_MATH_DEFINES
#include <cmath>

成为我文件中的第一件事(我不使用PCH,所以如果您是PCH,则必须在之后#include "stdafx.h"),然后突然编译完美。

尝试将其向上移动到页面上方。完全不确定为什么会导致问题。

编辑:想通了。该#include <math.h>CMATH的头球后卫内发生。这意味着#includes列表中更高的内容包括cmath没有#define指定的内容。 math.h是专门设计的,因此您可以再次将其包含在现在已更改为add M_PI等的定义中cmath。情况并非如此。因此,#define _USE_MATH_DEFINES在添加其他内容之前,您需要确定自己。希望能为您清除它:)

失败包括math.h已经指出的使用非标准C / C ++ :)

编辑2:或正如David在评论中指出的,只是使自己成为定义值的常量,并且无论如何您都可以携带一些东西:)


之前定义它stdafx.h是我以前遇到过的这种行为问题。
Alok保存

@Als:不,不是。。。已经破解了,并在上面的编辑中解释了:)
Goz

好吧,这是要做的第一件事,将其保留在我要求OP进行同样操作的所有其他杂项之上。由于您的回答说出了为什么应该在标准标头之前的原因,因此任何方式都会删除我的回答。
Alok保存

3
例如,如果在执行此操作之前#include <math.h>发生了其他事情,您将得到此行为。也就是说,标准中没有任何内容要求<cmath>必须包含<math.h>,或者必须启用<math.h>中的非标准定义。不幸的是,M_PI是非标准的。对于可移植性,最好的办法是自己定义。更好的是,将其const static double设为而不是#defined值。
David Hammen

1
@David Hammen:同意..自己定义绝对是最方便的选择:)
Goz

14

考虑将开关/ D_USE_MATH_DEFINES添加到编译命令行,或在项目设置中定义宏。这会将符号拖到包含文件和源文件的所有可触及的黑暗角落,从而使源文件在多个平台上均清晰可见。如果为整个项目全局设置它,则以后不会在新文件中忘记它。


从Visual Studio操作时,这可能是一个很好的答案,但请注意,通过Matlab mex命令行(我使用mex -D_USE_MATH_DEFINES)进行编译时,它并没有为我解决问题。仅/Y-在某些Matlab mexoptions文件中添加smewhere有助于...
aka.nice19,19年

9

这对我有用:

#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>

using namespace std;

int main()
{
    cout << M_PI << endl;

    return 0;
}

编译并打印pi喜欢的是应该:cl /O2 main.cpp /link /out:test.exe

您发布的代码和您尝试编译的代码必须不匹配。

确保在您的#define。之前没有引入任何预编译的头文件。


您正在使用哪个版本的VisualStudio?
Goz

使用Visual C ++ 2010 Express Edition的命令行编译器,该程序对我来说运行良好。唯一的区别是,我使用了<cstdio>中的std :: printf()而不是<iostream>中的std :: cout。

4
是的,我想出了它的原因……是因为从cmath的标头防护中调用maths.h……因此maths.h已包含在没有#define的早期标头中:)
Goz

4

在构建控制台或Windows应用程序时,这在VS Community 2015和2017中仍然是一个问题。如果项目是使用预编译头创建的,则预编译头显然会任何#include 之前加载,因此即使#define _USE_MATH_DEFINES是第一行,也不会编译。#包括math.h而不是cmath并没有什么不同。

我能找到的唯一解决方案是从一个空项目开始(对于简单的控制台或嵌入式系统应用程序),或者在命令行参数中添加/ Y-,从而关闭了预编译标头的加载。

有关禁用预编译头的信息,请参见例如 https://msdn.microsoft.com/en-us/library/1hy7a92h.aspx

如果MS可以更改/修复此问题,那将是很好的。我在一所大型大学教授入门编程课程,并向新手解释这一点,直到他们犯了错误并在一个下午左右的时间里为之苦苦挣扎。


我确认对于C代码#include <math.h>
aka.nice

1
这在VS中根本不是问题。_USE_MATH_DEFINES应该在包含任何标题之前定义。通常通过项目设置或配置标头。假设仅将其放在第一行将导致在所有标头之前定义它是错误的。
user7860670

1

根据Microsoft有关数学常数的文档:

该文件ATLComTime.h包括math.h在发布模式下构建项目的时间。如果在也包含的项目中使用一个或多个数学常数ATLComTime.h,则必须先定义,_USE_MATH_DEFINES然后再包含ATLComTime.h

文件ATLComTime.h可能会间接包含在您的项目中。在我的情况下,包括的可能顺序是:

项目"stdafx.h"→交通<afxdtctl.h>→交通<afxdisp.h>→交通<ATLComTime.h>→交通<math.h>


这也许可以解释为什么/ Y-(禁用stdafx.h)可以解决问题,但是仍然需要解释为什么-D_USE_MATH_DEFINES在默认的编译器设置中提供不足以解决问题的原因……因为编译是通过Matlab mex命令进行的问题,跟踪并不是很明显...
aka.nice19,19年

0

根据user7860670的建议,右键单击项目,选择属性,导航到C / C ++-> Preprocessor并添加 _USE_MATH_DEFINES到Preprocessor Definitions。

那对我有用。


0

有了CMake,那将是

add_compile_definitions(_USE_MATH_DEFINES)

在中CMakeLists.txt

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.