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?


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 :)


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).


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.


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.


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>


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.


0

Com CMake seria apenas

add_compile_definitions(_USE_MATH_DEFINES)

no CMakeLists.txt.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.