M_PI funktioniert mit math.h, jedoch nicht mit cmath in Visual Studio

94

Ich verwende Visual Studio 2010. Ich habe gelesen, dass es in C ++ besser ist, <cmath>als zu verwenden <math.h>.

Aber im Programm versuche ich zu schreiben (Win32-Konsolenanwendung, leeres Projekt), wenn ich schreibe:

#define _USE_MATH_DEFINES
#include <math.h>

es kompiliert, während wenn ich schreibe

#define _USE_MATH_DEFINES
#include <cmath>

es scheitert mit

Fehler C2065: 'M_PI': nicht deklarierter Bezeichner

Es ist normal? Ist es wichtig, ob ich cmath oder math.h verwende? Wenn ja, wie kann ich es mit cmath zum Laufen bringen?

UPDATE : Wenn ich _USE_MATH_DEFINES in der GUI definiere, funktioniert es. Irgendein Hinweis, warum dies geschieht?

Hyperknoten
quelle
Sind Ihre Quelldateien .c oder .cpp?
Schweizer
1
Schweizer: sollte hier keine Rolle spielen.
Rubenvb
Sehr seltsam ... Ich kann bestätigen, dass ich das gleiche Problem mit VS2010 habe ... Ich untersuche, was das Durchkommen der Definition verhindert ... es muss irgendwo unbestimmt sein ... aber ich kann nicht herausfinden, wo
Goz
Mit x86 wird der Fehler C2065 beanstandet. Mit x64 gibt es dann keinen Fehler.
user2616989

Antworten:

115

Interessanterweise habe ich dies in einer meiner Apps überprüft und den gleichen Fehler erhalten.

Ich habe eine Weile in den Headern nachgesehen, um _USE_MATH_DEFINESfestzustellen, ob etwas undefiniert war, und nichts gefunden.

Also habe ich die bewegt

#define _USE_MATH_DEFINES
#include <cmath>

um das erste in meiner Datei zu sein (ich benutze keine PCHs, wenn Sie es sind, müssen Sie es nach dem haben #include "stdafx.h") und plötzlich wird es perfekt kompiliert.

Versuchen Sie, es höher auf der Seite zu verschieben. Völlig unsicher, warum dies zu Problemen führen würde.

Edit : Hab es herausgefunden. Das #include <math.h>tritt innerhalb der Header-Wachen von cmath auf. Dies bedeutet, dass etwas weiter oben in der Liste der #includes cmathohne das #defineangegebene enthalten ist. math.hwurde speziell entwickelt, damit Sie es wieder in die Definition aufnehmen können, die jetzt geändert wurde, um sie hinzuzufügen M_PIusw. Dies ist bei NICHT der Fall cmath. Sie müssen sich also vergewissern, #define _USE_MATH_DEFINESbevor Sie etwas anderes hinzufügen. Hoffe das klärt es für dich auf :)

Andernfalls verwenden math.hSie nicht standardmäßiges C / C ++, wie bereits erwähnt :)

Edit 2 : Oder wie David in den Kommentaren betont, machen Sie sich einfach zu einer Konstante, die den Wert definiert, und Sie haben sowieso etwas Tragbareres :)

Goz
quelle
Nachdem ich es zuvor definiert habe, stdafx.hist das OP-Problem, mit dem ich dieses Verhalten zuvor konfrontiert habe.
Alok Save
@ Als: Nein, es ist nicht so ... habe es geknackt und in meiner Bearbeitung oben erklärt :)
Goz
Nun, das war das erste, was zu tun war. Behalten Sie es über allen anderen Heasdern. Ich habe das OP gebeten, dasselbe zu tun. Auf jeden Fall wird meine Antwort gelöscht, da Ihre Antwort den tatsächlichen Grund angibt, warum sie vor Standard-Headern stehen sollte.
Alok Save
3
Sie würden dieses Verhalten beispielsweise erhalten, wenn #include <math.h> vor Ihnen etwas anderes passiert wäre. Der Standard enthält jedoch nichts, was besagt, dass <cmath> <math.h> enthalten muss oder dass die nicht standardmäßigen Definitionen in <math.h> aktiviert werden müssen. Leider ist M_PI nicht Standard. Für die Portabilität ist es am besten, sie selbst zu definieren. Besser noch, machen Sie es const static doubleeher zu einem als zu einem # definierten Wert.
David Hammen
1
@ David Hammen: Einverstanden .. es selbst zu definieren ist definitiv die tragbarste Option :)
Goz
13

Erwägen Sie, den Schalter / D_USE_MATH_DEFINES zu Ihrer Kompilierungsbefehlszeile hinzuzufügen oder das Makro in den Projekteinstellungen zu definieren. Dadurch wird das Symbol in alle erreichbaren dunklen Ecken von Include- und Quelldateien gezogen, sodass Ihre Quelle für mehrere Plattformen sauber bleibt. Wenn Sie es global für das gesamte Projekt festlegen, werden Sie es später in einer neuen Datei nicht vergessen.

Thinkeye
quelle
Es ist wahrscheinlich eine gute Antwort, wenn Sie mit VisualStudio arbeiten, aber beachten Sie, dass es das Problem für mich beim Kompilieren über die Matlab mex-Befehlszeile (die ich verwendet habe mex -D_USE_MATH_DEFINES) nicht gelöst hat . Nur das Hinzufügen von /Y-smewhere in einer Matlab mexoptions-Datei hat geholfen ...
aka.nice
9

Das funktioniert bei mir:

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

using namespace std;

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

    return 0;
}

Kompiliert und druckt piwie es sein sollte : cl /O2 main.cpp /link /out:test.exe.

Der von Ihnen veröffentlichte Code und der Code, den Sie kompilieren möchten, müssen nicht übereinstimmen.

Stellen Sie sicher, dass keine vorkompilierten Header vor Ihrem eingezogen werden #define.

rubenvb
quelle
Welche Version von VisualStudio verwenden Sie?
Goz
Das gleiche Programm funktionierte für mich mit dem Befehlszeilen-Compiler von Visual C ++ 2010 Express Edition einwandfrei. Der einzige Unterschied ist, dass ich std :: printf () von <cstdio> anstelle von std :: cout von <iostream> verwendet habe.
4
Ja, ich habe es herausgefunden ... es liegt daran, dass maths.h innerhalb der Header-Wachen von cmath aufgerufen wird ... also wurde maths.h bereits aus einem früheren Header ohne das # define-Set aufgenommen :)
Goz
4

Dies ist in VS Community 2015 und 2017 immer noch ein Problem, wenn Konsolen- oder Windows-Apps erstellt werden. Wenn das Projekt mit vorkompilierten Headern erstellt wird, werden die vorkompilierten Header anscheinend vor einem der # Includes geladen. Selbst wenn #define _USE_MATH_DEFINES die erste Zeile ist, wird es nicht kompiliert. # Einschließlich math.h anstelle von cmath macht keinen Unterschied.

Die einzigen Lösungen, die ich finden kann, bestehen darin, entweder von einem leeren Projekt aus zu starten (für einfache Konsolen- oder eingebettete System-Apps) oder / Y- zu den Befehlszeilenargumenten hinzuzufügen, wodurch das Laden vorkompilierter Header deaktiviert wird.

Informationen zum Deaktivieren vorkompilierter Header finden Sie beispielsweise unter https://msdn.microsoft.com/en-us/library/1hy7a92h.aspx

Es wäre schön, wenn MS dies ändern / beheben würde. Ich unterrichte einführende Programmierkurse an einer großen Universität, und wenn ich dies Neulingen erkläre, wird dies erst dann deutlich, wenn sie den Fehler gemacht und etwa einen Nachmittag lang damit zu kämpfen haben.

user3533658
quelle
Ich bestätige, dass Hacking / Y- für mich funktioniert hat, für C-Code #include <math.h>
aka.nice
1
Dies ist in VS überhaupt kein Problem. _USE_MATH_DEFINESsollte vor dem Einfügen von Headern definiert werden. In der Regel entweder über die Projekteinstellung oder über den Konfigurationsheader. Es ist falsch anzunehmen, dass das einfache Setzen in die erste Zeile dazu führt, dass es vor allen Überschriften definiert wird.
user7860670
1

Laut Microsoft-Dokumentation zu Math Constants :

Die Datei ATLComTime.henthält, math.hwenn Ihr Projekt im Freigabemodus erstellt wird. Wenn Sie eine oder mehrere der mathematischen Konstanten in einem Projekt verwenden, das auch enthält ATLComTime.h, müssen Sie diese definieren, _USE_MATH_DEFINESbevor Sie sie einschließen ATLComTime.h.

Die Datei ATLComTime.hkann indirekt in Ihr Projekt aufgenommen werden. In meinem Fall war eine mögliche Reihenfolge der Aufnahme die folgende:

Projekte "stdafx.h"<afxdtctl.h><afxdisp.h><ATLComTime.h><math.h>

αλεχολυτ
quelle
Dies kann erklären, warum / Y- (stdafx.h deaktivieren) das Problem lösen würde, es bleibt jedoch zu erklären, warum das Bereitstellen -D_USE_MATH_DEFINESin den Standard-Compilereinstellungen nicht ausreicht, um das Problem zu lösen ... Da die Kompilierung über den Befehl Matlab mex für mich selbst erfolgte Problem, es ist nicht so offensichtlich zu verfolgen ...
aka.nice
0

Klicken Sie wie von user7860670 vorgeschlagen mit der rechten Maustaste auf das Projekt, wählen Sie Eigenschaften aus, navigieren Sie zu C / C ++ -> Präprozessor und fügen Sie _USE_MATH_DEFINESdie Präprozessordefinitionen hinzu.

Das hat bei mir funktioniert.

Den-Jason
quelle