M_PI funciona con math.h pero no con cmath en Visual Studio

94

Estoy usando Visual Studio 2010. He leído que en C ++ es mejor usar en <cmath>lugar de <math.h>.

Pero en el programa que estoy tratando de escribir (aplicación de consola Win32, proyecto vacío) si escribo:

#define _USE_MATH_DEFINES
#include <math.h>

compila, mientras que si escribo

#define _USE_MATH_DEFINES
#include <cmath>

falla con

error C2065: 'M_PI': identificador no declarado

¿Es normal? ¿Importa si uso cmath o math.h? Si es así, ¿cómo puedo hacer que funcione con cmath?

ACTUALIZACIÓN : si defino _USE_MATH_DEFINES en la GUI, funciona. ¿Alguna pista de por qué está pasando esto?

hipernudo
fuente
¿Son sus archivos de origen .co .cpp?
Suiza
1
Suiza: no debería importar aquí.
rubenvb
Muy extraño ... puedo confirmar que obtengo el mismo problema con VS2010 ... estoy investigando qué es lo que detiene el paso de la definición ... debe estar indefinido en alguna parte ... pero no puedo averiguar dónde
Goz
Con x86, se quejará del error C2065. Con x64, entonces no hay error.
user2616989

Respuestas:

116

Curiosamente, verifiqué esto en una aplicación mía y obtuve el mismo error.

Pasé un tiempo revisando los encabezados para ver si había algo debajo de la definición _USE_MATH_DEFINESy no encontré nada.

Así que moví el

#define _USE_MATH_DEFINES
#include <cmath>

para ser lo primero en mi archivo (no uso PCH, así que si lo eres, tendrás que tenerlo después #include "stdafx.h") y de repente se compila perfectamente.

Intente moverlo hacia arriba en la página. Sin embargo, estoy totalmente inseguro de por qué esto causaría problemas.

Editar : lo descubrí. El #include <math.h>ocurre dentro de los protectores de cabecera de cmath. Esto significa que algo más arriba en la lista de #includes se incluye cmathsin el #defineespecificado. math.hestá diseñado específicamente para que pueda incluirlo nuevamente con esa definición ahora cambiada para agregar, M_PIetc. Este NO es el caso con cmath. Por lo tanto, debe asegurarse #define _USE_MATH_DEFINESantes de incluir cualquier otra cosa. Espero que eso te aclare :)

Si no lo incluye math.h, está utilizando C / C ++ no estándar como ya se señaló :)

Edición 2 : O, como David señala en los comentarios, simplemente conviértase en una constante que defina el valor y, de todos modos, tendrá algo más portátil :)

Goz
fuente
Habiéndolo definido antes stdafx.hes el problema de los OPs. Me he enfrentado a este comportamiento antes.
Alok Save
@Als: No, no es eso ... lo he descifrado y explicado en mi edición anterior :)
Goz
Bueno, eso fue lo primero que hice, manténgalo por encima de todos los demás encabezados Le pedí al OP que hiciera lo mismo ... De todos modos, eliminaré mi respuesta ya que su respuesta dice la razón real por la que debería estar antes de los encabezados estándar.
Alok Save
3
Obtendría este comportamiento, por ejemplo, si algo más le sucediera a #include <math.h> antes que usted. Dicho esto, no hay nada en el estándar que diga que <cmath> tenga que incluir <math.h>, o que tenga que habilitar las definiciones no estándar en <math.h>. Desafortunadamente, M_PI no es estándar. Para la portabilidad, lo mejor que puede hacer es definirlo usted mismo. Mejor aún, const static doubleconviértalo en un valor en lugar de # definido.
David Hammen
1
@David Hammen: De acuerdo ... definirlo usted mismo es definitivamente la opción más portátil :)
Goz
14

Considere agregar el modificador / D_USE_MATH_DEFINES a su línea de comando de compilación, o definir la macro en la configuración del proyecto. Esto arrastrará el símbolo a todas las esquinas oscuras accesibles de los archivos de origen e inclusión, dejando su fuente limpia para múltiples plataformas. Si lo configura globalmente para todo el proyecto, no lo olvidará más adelante en un nuevo archivo (s).

Thinkeye
fuente
Probablemente sea una buena respuesta cuando se opera desde VisualStudio, pero tenga en cuenta que no me resolvió el problema al compilar a través de la línea de comando Matlab mex (que usé mex -D_USE_MATH_DEFINES). Solo /Y-ayudó agregar smewhere en algunos archivos de opciones de Matlab mexoptions ...
aka.nice
9

Esto funciona para mi:

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

using namespace std;

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

    return 0;
}

Compila y grabados picomo SI debe: cl /O2 main.cpp /link /out:test.exe.

Debe haber una discrepancia entre el código que ha publicado y el que está intentando compilar.

Asegúrese de que no haya encabezados precompilados antes de su #define.

rubenvb
fuente
¿Qué versión de VisualStudio estás usando?
Goz
El mismo programa funcionó bien para mí usando el compilador de línea de comandos de Visual C ++ 2010 Express Edition. La única diferencia es que usé std :: printf () de <cstdio> en lugar de std :: cout de <iostream>.
4
Sí, lo descubrí ... es porque maths.h se llama desde dentro de los guardias de encabezado de cmath ... así que maths.h ya se ha incluido desde un encabezado anterior sin el conjunto #define :)
Goz
4

Esto sigue siendo un problema en VS Community 2015 y 2017 al crear aplicaciones de consola o de Windows. Si el proyecto se crea con encabezados precompilados, los encabezados precompilados aparentemente se cargan antes que cualquiera de los #includes, por lo que incluso si #define _USE_MATH_DEFINES es la primera línea, no se compilará. # Incluir math.h en lugar de cmath no hace ninguna diferencia.

Las únicas soluciones que puedo encontrar son comenzar desde un proyecto vacío (para una consola simple o aplicaciones integradas del sistema) o agregar / Y- a los argumentos de la línea de comandos, lo que desactiva la carga de encabezados precompilados.

Para obtener información sobre cómo deshabilitar los encabezados precompilados, consulte, por ejemplo, https://msdn.microsoft.com/en-us/library/1hy7a92h.aspx

Sería bueno que MS cambiara / arreglara esto. Doy cursos de introducción a la programación en una gran universidad, y explicar esto a los novatos nunca se asimila hasta que cometen el error y luchan con él durante una tarde más o menos.

usuario3533658
fuente
confirmo que hackear / Y- funcionó para mí, para el código C #include <math.h>
conocido como agradable
1
Esto no es un problema en VS en absoluto. _USE_MATH_DEFINESdebe definirse antes de incluir cualquier encabezado. Normalmente, a través de la configuración del proyecto o mediante el encabezado de configuración. Es incorrecto suponer que simplemente ponerlo en la primera línea hará que se defina antes de todos los encabezados.
user7860670
1

Según la documentación de Microsoft sobre constantes matemáticas :

El archivo ATLComTime.hincluye math.hcuándo su proyecto está construido en modo de lanzamiento. Si usa una o más de las constantes matemáticas en un proyecto que también incluye ATLComTime.h, debe definir _USE_MATH_DEFINESantes de incluir ATLComTime.h.

El archivo ATLComTime.hpuede incluirse indirectamente en su proyecto. En mi caso, un posible orden de inclusión fue el siguiente:

proyecto's "stdafx.h"<afxdtctl.h><afxdisp.h><ATLComTime.h><math.h>

αλεχολυτ
fuente
Esto puede explicar por qué / Y- (deshabilitar stdafx.h) resolvería el problema, sin embargo, queda por explicar por qué proporcionar -D_USE_MATH_DEFINESla configuración predeterminada del compilador no es suficiente para resolver el problema ... Dado que la compilación se realizó a través del comando Matlab mex para el mío problema, no es tan obvio rastrear ...
conocido
0

Como lo sugirió el usuario 7860670, haga clic con el botón derecho en el proyecto, seleccione propiedades, navegue hasta C / C ++ -> Preprocesador y agregue _USE_MATH_DEFINESa las Definiciones del preprocesador.

Eso es lo que funcionó para mí.

Den-Jason
fuente
0

Con CMake solo sería

add_compile_definitions(_USE_MATH_DEFINES)

en CMakeLists.txt.

FLUXpartícula
fuente