M_PI funziona con math.h ma non con cmath in Visual Studio


94

Sto usando Visual Studio 2010. Ho letto che in C ++ è meglio usare <cmath>piuttosto che <math.h>.

Ma nel programma sto cercando di scrivere (applicazione console Win32, progetto vuoto) se scrivo:

#define _USE_MATH_DEFINES
#include <math.h>

compila, mentre se scrivo

#define _USE_MATH_DEFINES
#include <cmath>

fallisce con

errore C2065: "M_PI": identificatore non dichiarato

È normale? È importante se utilizzo cmath o math.h? Se sì, come posso farlo funzionare con cmath?

AGGIORNAMENTO : se definisco _USE_MATH_DEFINES nella GUI, funziona. Qualche indizio sul perché sta succedendo?


I tuoi file sorgente sono .c o .cpp?
Svizzera

1
Svizzero: non dovrebbe importare qui.
rubenvb

Molto strano ... posso confermare di avere lo stesso problema con VS2010 ... sto esaminando cosa sta impedendo il passaggio della definizione ... deve essere indefinito da qualche parte ... ma non riesco a capire dove
Goz

Con x86, si lamenterà dell'errore C2065. Con x64, non ci sono errori.
user2616989

Risposte:


116

È interessante notare che l'ho controllato su una mia app e ho ricevuto lo stesso errore.

Ho passato un po 'di tempo a controllare le intestazioni per vedere se c'era qualcosa di indefinito _USE_MATH_DEFINESe non ho trovato nulla.

Quindi ho spostato il file

#define _USE_MATH_DEFINES
#include <cmath>

per essere la prima cosa nel mio file (non uso PCH quindi se lo sei dovrai averlo dopo il #include "stdafx.h") e improvvisamente si compila perfettamente.

Prova a spostarlo più in alto nella pagina. Totalmente incerto sul motivo per cui ciò potrebbe causare problemi.

Modifica : capito. Si #include <math.h>verifica all'interno delle protezioni dell'intestazione di cmath. Ciò significa che qualcosa di più in alto nell'elenco di #include è incluso cmathsenza il valore #definespecificato. math.hè specificamente progettato in modo che tu possa includerlo di nuovo con quella definizione ora modificata per aggiungere M_PIecc. Questo NON è il caso di cmath. Quindi devi assicurarti #define _USE_MATH_DEFINESdi includere qualsiasi altra cosa. Spero che questo ti renda tutto più chiaro :)

In caso contrario, math.hsi utilizza solo C / C ++ non standard come già sottolineato :)

Modifica 2 : O, come sottolinea David nei commenti, renditi una costante che definisce il valore e hai comunque qualcosa di più portatile :)


Averlo definito prima stdafx.hè il problema dei PO che ho affrontato prima questo comportamento.
Alok Save

@Als: No, non è quello ... l'ho risolto e spiegato nella mia modifica sopra :)
Goz

Ebbene questa è stata la prima cosa da fare, tienilo al di sopra di tutti gli altri heasders Ho chiesto all'OP di fare lo stesso .... Comunque cancellerò la mia risposta poiché la tua risposta dice il vero motivo del perché dovrebbe essere prima delle intestazioni standard.
Alok Save

3
Si otterrebbe questo comportamento, ad esempio, se prima di te accadesse qualcos'altro a #include <math.h>. Detto questo, non c'è nulla nello standard che dica che <cmath> deve includere <math.h> o che deve abilitare le definizioni non standard in <math.h>. Sfortunatamente, M_PI non è standard. Per la portabilità, la cosa migliore da fare è definirla da soli. Meglio ancora, const static doublerendilo un valore piuttosto che un #defined.
David Hammen

1
@David Hammen: d'accordo .. definirlo da soli è sicuramente l'opzione più portatile :)
Goz

14

Considera l'idea di aggiungere l'opzione / D_USE_MATH_DEFINES alla riga di comando della compilazione o di definire la macro nelle impostazioni del progetto. Questo trascinerà il simbolo su tutti gli angoli scuri raggiungibili dei file di inclusione e di origine, lasciando la tua fonte pulita per più piattaforme. Se lo imposti globalmente per l'intero progetto, non lo dimenticherai più tardi in un nuovo file.


Probabilmente è una buona risposta quando si opera da VisualStudio, ma si noti che non ha risolto il problema per me durante la compilazione tramite la riga di comando di Matlab mex (ho usato mex -D_USE_MATH_DEFINES). Solo l'aggiunta di /Y-smewhere in alcuni file di Matlab mexoptions ha aiutato ...
aka.nice

9

Questo funziona per me:

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

using namespace std;

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

    return 0;
}

Compila e stampa picome Is dovrebbe: cl /O2 main.cpp /link /out:test.exe.

Deve esserci una mancata corrispondenza tra il codice che hai pubblicato e quello che stai cercando di compilare.

Assicurati che non siano presenti intestazioni precompilate prima del tuo #define.


Quale versione di VisualStudio stai usando?
Goz

Lo stesso programma ha funzionato bene per me utilizzando il compilatore a riga di comando di Visual C ++ 2010 Express Edition. L'unica differenza è che ho usato std :: printf () da <cstdio> invece di std :: cout da <iostream>.

4
Sì, l'ho capito ... è perché maths.h viene chiamato dalle protezioni dell'intestazione di cmath ... quindi maths.h è già stato incluso da un'intestazione precedente senza il set #define :)
Goz

4

Questo è ancora un problema in VS Community 2015 e 2017 durante la creazione di app per console o Windows. Se il progetto viene creato con intestazioni precompilate, le intestazioni precompilate vengono apparentemente caricate prima di qualsiasi #include, quindi anche se #define _USE_MATH_DEFINES è la prima riga, non verrà compilato. #including math.h invece di cmath non fa differenza.

Le uniche soluzioni che riesco a trovare sono iniziare da un progetto vuoto (per console semplici o app di sistema embedded) o aggiungere / Y- agli argomenti della riga di comando, che disattiva il caricamento delle intestazioni precompilate.

Per informazioni sulla disabilitazione delle intestazioni precompilate, vedere ad esempio https://msdn.microsoft.com/en-us/library/1hy7a92h.aspx

Sarebbe bello se MS cambiasse / risolvesse questo problema. Insegno a corsi introduttivi di programmazione in una grande università e spiegarlo ai neofiti non viene mai coinvolto finché non hanno commesso l'errore e ci hanno lottato per un pomeriggio o giù di lì.


confermo che l'hacking / Y- ha funzionato per me, per il codice C #include <math.h>
aka.nice

1
Questo non è affatto un problema in VS. _USE_MATH_DEFINESdeve essere definito prima di includere eventuali intestazioni. In genere tramite l'impostazione del progetto o tramite l'intestazione di configurazione. È sbagliato presumere che semplicemente inserendolo nella prima riga verrà definito prima di tutte le intestazioni.
user7860670

1

Secondo la documentazione Microsoft sulle costanti matematiche :

Il file ATLComTime.hinclude math.hquando il progetto viene creato in modalità di rilascio. Se utilizzi una o più costanti matematiche in un progetto che include anche ATLComTime.h, devi definirle _USE_MATH_DEFINESprima di includerle ATLComTime.h.

Il file ATLComTime.hpuò essere incluso indirettamente nel progetto. Nel mio caso un possibile ordine di inclusione era il seguente:

del progetto "stdafx.h"<afxdtctl.h><afxdisp.h><ATLComTime.h><math.h>


Questo potrebbe spiegare perché / Y- (disabilita stdafx.h) risolverebbe il problema, tuttavia resta da spiegare perché fornire -D_USE_MATH_DEFINESle impostazioni predefinite del compilatore non è sufficiente per risolvere il problema ... Poiché la compilazione è stata eseguita tramite il comando Matlab mex per conto mio problema, non è così ovvio rintracciare ...
aka

0

Come suggerito da user7860670, fare clic con il pulsante destro del mouse sul progetto, selezionare proprietà, accedere a C / C ++ -> Preprocessore e aggiungere _USE_MATH_DEFINESalle definizioni del preprocessore.

Questo è ciò che ha funzionato per me.


0

Con CMake sarebbe solo

add_compile_definitions(_USE_MATH_DEFINES)

in CMakeLists.txt.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.