M_PI funciona com math.h, mas não com cmath no Visual Studio

94

Estou usando o Visual Studio 2010. Li que em C ++ é melhor usar <cmath>do que usar <math.h>.

Mas no programa que estou tentando escrever (aplicativo de console Win32, projeto vazio) se eu escrever:

#define _USE_MATH_DEFINES
#include <math.h>

ele compila, enquanto se eu escrever

#define _USE_MATH_DEFINES
#include <cmath>

falha com

erro C2065: 'M_PI': identificador não declarado

Isso é normal? Faz diferença se eu usar cmath ou math.h? Se sim, como posso fazer funcionar com o cmath?

ATUALIZAÇÃO : se eu definir _USE_MATH_DEFINES na GUI, funciona. Alguma pista de por que isso está acontecendo?

hyperknot
fonte
Seus arquivos de origem são .c ou .cpp?
Suíça
1
Suíço: não deve importar aqui.
rubenvb
Muito estranho ... posso confirmar que tenho o mesmo problema com VS2010 ... estou investigando o que está impedindo a definição de passar ... deve estar indefinido em algum lugar ... mas não consigo descobrir onde
Goz
Com x86, ele irá reclamar do erro C2065. Com x64, não há erro.
user2616989

Respostas:

116

Curiosamente, verifiquei isso em um aplicativo meu e recebi o mesmo erro.

Passei um tempo verificando os cabeçalhos para ver se havia algo undef'ing o _USE_MATH_DEFINESe não encontrei nada.

Então mudei o

#define _USE_MATH_DEFINES
#include <cmath>

para ser a primeira coisa no meu arquivo (eu não uso PCHs, então se você usar terá que tê-lo depois de #include "stdafx.h") e de repente compilar perfeitamente.

Tente movê-lo para cima na página. Totalmente inseguro quanto ao motivo disso causar problemas.

Edit : Descobri isso. O #include <math.h>ocorre dentro dos protetores de cabeçalho de cmath. Isso significa que algo mais acima na lista de #includes está incluindo cmathsem o #defineespecificado. math.hé projetado especificamente para que você possa incluí-lo novamente com aquela definição agora alterada para adicionar M_PIetc. Este NÃO é o caso de cmath. Portanto, você precisa ter certeza #define _USE_MATH_DEFINESantes de incluir qualquer outra coisa. Espero que tudo se esclareça para você :)

Se não incluir, math.hvocê está usando C / C ++ não padrão, como já apontado :)

Edição 2 : Ou, como David aponta nos comentários, torne-se uma constante que defina o valor e você terá algo mais portátil de qualquer maneira :)

Goz
fonte
Tendo definido isso antes, stdafx.hé o problema de OPs que já enfrentei antes.
Alok Save
@Als: Nah, não é isso ... quebrei e expliquei na minha edição acima :)
Goz
Bem, essa foi a primeira coisa a fazer, mantê-lo acima de todos os outros heasders. Eu pedi ao OP para fazer o mesmo ... De qualquer forma, irei deletar minha resposta, já que sua resposta diz o motivo real do porque deveria estar antes dos cabeçalhos padrão.
Alok Save
3
Você obteria este comportamento, por exemplo, se algo mais acontecesse a #include <math.h> antes de você. Dito isso, não há nada no padrão que diga que <cmath> deve incluir <math.h>, ou que deve habilitar as definições não padrão em <math.h>. Infelizmente, M_PI não é padrão. Para portabilidade, a melhor coisa a fazer é definir você mesmo. Melhor ainda, torne-o um valor em const static doublevez de #defined.
David Hammen
1
@David Hammen: Concordo .. definir você mesmo é definitivamente a opção mais portátil :)
Goz
14

Considere adicionar a opção / D_USE_MATH_DEFINES à linha de comando de compilação ou definir a macro nas configurações do projeto. Isso arrastará o símbolo para todos os cantos escuros acessíveis dos arquivos de inclusão e fonte, deixando sua fonte limpa para várias plataformas. Se você configurá-lo globalmente para todo o projeto, não o esquecerá mais tarde em um (s) novo (s) arquivo (s).

Thinkeye
fonte
Provavelmente é uma boa resposta ao operar no VisualStudio, mas observe que não resolveu o problema para mim ao compilar através da linha de comando mex do Matlab (eu usei mex -D_USE_MATH_DEFINES). Apenas adicionar /Y-smewhere em algum arquivo mexoptions do Matlab ajudou ...
aka.nice
9

Isso funciona para mim:

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

using namespace std;

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

    return 0;
}

Compila e imprime picomo deveria:cl /O2 main.cpp /link /out:test.exe .

Deve haver uma incompatibilidade entre o código que você postou e o que está tentando compilar.

Certifique-se de que não haja cabeçalhos pré-compilados puxados antes de seu #define.

rubenvb
fonte
Qual versão do VisualStudio você está usando?
Goz
O mesmo programa funcionou bem para mim usando o compilador de linha de comando do Visual C ++ 2010 Express Edition. A única diferença é que usei std :: printf () de <cstdio> em vez de std :: cout de <iostream>.
4
Sim, eu descobri ... é porque maths.h é chamado de dentro dos guardas de cabeçalho de cmath ... então maths.h já foi incluído de um cabeçalho anterior sem o conjunto #define :)
Goz
4

Isso ainda é um problema no VS Community 2015 e 2017 ao construir aplicativos de console ou do Windows. Se o projeto é criado com cabeçalhos pré-compilados, os cabeçalhos pré-compilados são aparentemente carregados antes qualquer um dos #includes, portanto, mesmo se #define _USE_MATH_DEFINES for a primeira linha, ele não será compilado. #incluir math.h em vez de cmath não faz diferença.

As únicas soluções que posso encontrar são iniciar a partir de um projeto vazio (para console simples ou aplicativos de sistema embutido) ou adicionar / Y- aos argumentos de linha de comando, o que desativa o carregamento de cabeçalhos pré-compilados.

Para obter informações sobre como desabilitar cabeçalhos pré-compilados, consulte por exemplo https://msdn.microsoft.com/en-us/library/1hy7a92h.aspx

Seria bom se a MS mudasse / corrigisse isso. Eu ensino cursos introdutórios de programação em uma grande universidade, e explicar isso aos novatos nunca cai na cabeça até que eles cometam o erro e lutassem com ele por uma tarde ou assim.

user3533658
fonte
eu confirmo que hackear / Y- funcionou para mim, para o código C #include <math.h>
aka.nice
1
Isso não é um problema no VS. _USE_MATH_DEFINESdeve ser definido antes de incluir qualquer cabeçalho. Normalmente, por meio da definição do projeto ou do cabeçalho de configuração. É errado assumir que simplesmente colocá-lo na primeira linha fará com que seja definido antes de todos os cabeçalhos.
user7860670 01 de
1

De acordo com a documentação da Microsoft sobre Constantes Matemáticas :

O arquivo ATLComTime.hinclui math.hquando seu projeto é construído no modo Release. Se você usar uma ou mais constantes matemáticas em um projeto que também inclui ATLComTime.h, você deve definir _USE_MATH_DEFINESantes de incluir ATLComTime.h.

O arquivo ATLComTime.hpode ser incluído indiretamente em seu projeto. No meu caso, uma possível ordem de inclusão era a seguinte:

do projeto "stdafx.h"<afxdtctl.h><afxdisp.h><ATLComTime.h><math.h>

αλεχολυτ
fonte
Isso pode explicar por que / Y- (desativar stdafx.h) resolveria o problema, no entanto, resta explicar por que fornecer -D_USE_MATH_DEFINESas configurações do compilador padrão não é suficiente para resolver o problema ... Já que a compilação foi feita por meio do comando Matlab mex para mim problema, não é tão óbvio de rastrear ...
aka.nice
0

Conforme sugerido pelo usuário7860670, clique com o botão direito do mouse no projeto, selecione propriedades, navegue até C / C ++ -> Pré-processador e adicione _USE_MATH_DEFINES às Definições do pré-processador.

Isso é o que funcionou para mim.

Den-Jason
fonte
0

Com CMake seria apenas

add_compile_definitions(_USE_MATH_DEFINES)

no CMakeLists.txt.

FLUXpartícula
fonte