M_PI współpracuje z math.h, ale nie z cmath w programie Visual Studio

96

Używam Visual Studio 2010. Czytałem, że w C ++ lepiej jest używać <cmath>niż <math.h>.

Ale w programie próbuję pisać (aplikacja konsoli Win32, pusty projekt) jeśli napiszę:

#define _USE_MATH_DEFINES
#include <math.h>

kompiluje się, gdy piszę

#define _USE_MATH_DEFINES
#include <cmath>

to zawodzi

błąd C2065: „M_PI”: niezadeklarowany identyfikator

Jest to normalne? Czy to ma znaczenie, czy używam cmath czy math.h? Jeśli tak, jak mogę sprawić, by działało z cmath?

UPDATE : jeśli zdefiniuję _USE_MATH_DEFINES w GUI, to działa. Jakieś wskazówki, dlaczego tak się dzieje?

hyperknot
źródło
Czy Twoje pliki źródłowe to .c czy .cpp?
Szwajcaria
1
Swiss: nie powinno mieć tu znaczenia.
rubenvb
Bardzo dziwne ... Mogę potwierdzić, że mam ten sam problem z VS2010 ... przyglądam się temu, co powstrzymuje definicję przed przejściem ... musi być gdzieś undef'd ... ale nie mogę dowiedzieć się, gdzie
Goz
W przypadku x86 będzie narzekać na błąd C2065. W przypadku x64 nie ma błędu.
user2616989

Odpowiedzi:

117

Co ciekawe, sprawdziłem to w mojej aplikacji i otrzymałem ten sam błąd.

Spędziłem trochę czasu sprawdzając nagłówki, aby zobaczyć, czy coś jest niezdefiniowane _USE_MATH_DEFINESi nic nie znalazłem.

Więc przeniosłem

#define _USE_MATH_DEFINES
#include <cmath>

być pierwszą rzeczą w moim pliku (nie używam PCH, więc jeśli jesteś, będziesz musiał to mieć po #include "stdafx.h") i nagle kompiluje się idealnie.

Spróbuj przenieść go wyżej w górę strony. Zupełnie nie jestem pewien, dlaczego mogłoby to powodować problemy.

Edycja : rozgryzłem to. #include <math.h>Zachodzi wewnątrz nagłówka cmath za strażników. Oznacza to, że coś znajdującego się wyżej na liście #includes jest włączanie cmathbez #defineokreślonego. math.hjest specjalnie zaprojektowany, aby można go było ponownie dołączyć do definicji, teraz zmieniono na dodanie M_PIitd. NIE jest to przypadek cmath. Dlatego musisz się upewnić, #define _USE_MATH_DEFINESzanim dołączysz cokolwiek innego. Mam nadzieję, że to wyjaśnia wszystko :)

Jeśli to nie wystarczy math.h, używasz niestandardowego C / C ++, jak już wspomniano :)

Edycja 2 : Lub jak wskazuje David w komentarzach, po prostu stwórz sobie stałą, która definiuje wartość, a i tak masz coś bardziej przenośnego :)

Goz
źródło
Zdefiniowanie tego wcześniej stdafx.hjest problemem PO, z którym miałem do czynienia już wcześniej.
Alok Save
@Als: Nie, to nie tak ... złamałem to i wyjaśniłem w mojej edycji powyżej :)
Goz
Cóż, to była pierwsza rzecz do zrobienia, trzymaj ją ponad wszystkimi innymi heasderami, o które poprosiłem OP, aby zrobił to samo ... W każdym razie usunie moją odpowiedź, ponieważ twoja odpowiedź podaje rzeczywisty powód, dla którego powinna być przed standardowymi nagłówkami.
Alok Zapisz
3
Możesz uzyskać takie zachowanie, na przykład, jeśli coś innego wydarzyło się przed #include <math.h>. To powiedziawszy, w standardzie nie ma nic, co mówi, że <cmath> musi zawierać <math.h> lub że musi włączać niestandardowe definicje w <math.h>. Niestety M_PI jest niestandardowy. Jeśli chodzi o przenośność, najlepiej zdefiniować ją samodzielnie. Jeszcze lepiej, uczyń to const static doubleraczej niż wartością zdefiniowaną.
David Hammen,
1
@David Hammen: Zgoda ... samodzielne zdefiniowanie tego jest zdecydowanie najbardziej przenośną opcją :)
Goz.
14

Rozważ dodanie przełącznika / D_USE_MATH_DEFINES do wiersza poleceń kompilacji lub zdefiniowanie makra w ustawieniach projektu. Spowoduje to przeciągnięcie symbolu do wszystkich osiągalnych ciemnych rogów plików dołączanych i źródłowych, pozostawiając źródło czyste na wielu platformach. Jeśli ustawisz go globalnie dla całego projektu, nie zapomnisz go później w nowym pliku (ach).

Thinkeye
źródło
Prawdopodobnie jest to dobra odpowiedź podczas pracy z VisualStudio, ale zauważ, że nie rozwiązało to problemu podczas kompilacji przez wiersz poleceń Matlab mex (użyłem mex -D_USE_MATH_DEFINES). /Y-Pomogło tylko dodanie czegoś w jakimś pliku meksykańskim Matlaba ...
aka.nice
10

To działa dla mnie:

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

using namespace std;

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

    return 0;
}

Kompiluje i drukuje pipodobny powinien: cl /O2 main.cpp /link /out:test.exe.

Musi istnieć niezgodność w opublikowanym kodzie i tym, który próbujesz skompilować.

Upewnij się, że nie ma żadnych prekompilowanych nagłówków, które są pobierane przed #define.

rubenvb
źródło
Jakiej wersji VisualStudio używasz?
Goz
Ten sam program działał dobrze dla mnie, używając kompilatora wiersza poleceń Visual C ++ 2010 Express Edition. Jedyną różnicą jest to, że użyłem std :: printf () z <cstdio> zamiast std :: cout z <iostream>.
5
Tak I zdobione go ... jego ponieważ maths.h nazywany jest od wewnątrz osłon nagłówka cmath za ... więc maths.h zostało już zawarte z wcześniejszego nagłówka bez zestawu #define :)
Goz
4

Jest to nadal problem występujący w VS Community 2015 i 2017 podczas tworzenia aplikacji na konsolę lub Windows. Jeśli projekt jest tworzony z prekompilowanymi nagłówkami, prekompilowane nagłówki są najwyraźniej ładowane przed którymkolwiek z #includes, więc nawet jeśli #define _USE_MATH_DEFINES jest pierwszą linią, nie zostanie skompilowany. # Włączanie math.h zamiast cmath nie robi różnicy.

Jedyne rozwiązania, które mogę znaleźć, to albo zacząć od pustego projektu (dla prostej konsoli lub aplikacji systemu wbudowanego), albo dodać / Y- do argumentów wiersza poleceń, co wyłącza ładowanie prekompilowanych nagłówków.

Aby uzyskać informacje na temat wyłączania prekompilowanych nagłówków, zobacz na przykład https://msdn.microsoft.com/en-us/library/1hy7a92h.aspx

Byłoby miło, gdyby MS to zmieniło / naprawiło. Prowadzę wstępne kursy programowania na dużym uniwersytecie i wyjaśniam to początkującym, dopóki nie popełnią błędu i nie zmagają się z nim przez jakieś popołudnie.

user3533658
źródło
Potwierdzam, że hacking / Y- zadziałał dla mnie, dla kodu C #include <math.h>
aka.nice
1
To w ogóle nie jest problemem w VS. _USE_MATH_DEFINESnależy zdefiniować przed dołączeniem jakichkolwiek nagłówków. Zwykle za pomocą ustawień projektu lub nagłówka konfiguracji. Błędem jest zakładanie, że zwykłe umieszczenie go w pierwszej linii spowoduje, że zostanie zdefiniowany przed wszystkimi nagłówkami.
user7860670
1

Zgodnie z dokumentacją Microsoft dotyczącą stałych matematycznych :

Plik ATLComTime.hzawiera informację, math.hkiedy projekt jest zbudowany w trybie wydania. Jeśli używasz jednej lub więcej stałych matematycznych w projekcie, który również zawiera ATLComTime.h, musisz zdefiniować _USE_MATH_DEFINESprzed dołączeniem ATLComTime.h.

Plik ATLComTime.hmoże być pośrednio dołączony do twojego projektu. W moim przypadku jedna z możliwych kolejności włączenia była następująca:

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

αλεχολυτ
źródło
To może wyjaśniać, dlaczego / Y- (wyłącz stdafx.h) rozwiązałoby problem, jednak pozostaje wyjaśnienie, dlaczego podanie -D_USE_MATH_DEFINESdomyślnych ustawień kompilatora nie wystarczy do rozwiązania problemu ... Ponieważ kompilacja była za pomocą polecenia Matlab mex dla mojego własnego problem, śledzenie nie jest takie oczywiste ...
aka.nice
1

Z CMake po prostu by tak było

add_compile_definitions(_USE_MATH_DEFINES)

w CMakeLists.txt.

FLUXparticle
źródło
0

Zgodnie z sugestią użytkownika7860670 kliknij projekt prawym przyciskiem myszy, wybierz właściwości, przejdź do C / C ++ -> Preprocessor i dodaj _USE_MATH_DEFINESdo definicji preprocesora.

To mi się udało.

Den-Jason
źródło