M_PI fonctionne avec math.h mais pas avec cmath dans Visual Studio

94

J'utilise Visual Studio 2010. J'ai lu qu'en C ++, il est préférable d'utiliser <cmath>plutôt que <math.h>.

Mais dans le programme, j'essaye d'écrire (application console Win32, projet vide) si j'écris:

#define _USE_MATH_DEFINES
#include <math.h>

il compile, alors que si j'écris

#define _USE_MATH_DEFINES
#include <cmath>

ça échoue avec

erreur C2065: 'M_PI': identifiant non déclaré

Est-ce normal? Est-ce important que j'utilise cmath ou math.h? Si oui, comment puis-je le faire fonctionner avec cmath?

MISE À JOUR : si je définis _USE_MATH_DEFINES dans l'interface graphique, cela fonctionne. Une idée pourquoi cela se produit?

hyperknot
la source
Vos fichiers sources sont-ils .c ou .cpp?
Suisse
1
Suisse: ça n'a pas d'importance ici.
rubenvb
Très étrange ... je peux confirmer que j'ai le même problème avec VS2010 ... je regarde ce qui empêche la définition de passer ... il doit être indéfini quelque part ... mais je ne peux pas savoir où
Goz
Avec x86, il se plaindra de l'erreur C2065. Avec x64, il n'y a pas d'erreur.
user2616989

Réponses:

116

Fait intéressant, j'ai vérifié cela sur une de mes applications et j'ai eu la même erreur.

J'ai passé un certain temps à vérifier les en-têtes pour voir s'il y avait quelque chose d'indéfaillable _USE_MATH_DEFINESet je n'ai rien trouvé.

Alors j'ai déplacé le

#define _USE_MATH_DEFINES
#include <cmath>

pour être la première chose dans mon fichier (je n'utilise pas de PCH donc si vous l'êtes vous devrez l'avoir après le #include "stdafx.h") et du coup il se compile parfaitement.

Essayez de le déplacer plus haut sur la page. Je ne sais absolument pas pourquoi cela causerait des problèmes.

Edit : compris. Le #include <math.h>se produit dans les gardes d'en-tête de cmath. Cela signifie que quelque chose de plus haut dans la liste des #includes est inclus cmathsans le #definespécifié. math.hest spécifiquement conçu pour que vous puissiez l'inclure à nouveau avec cette définition maintenant modifiée pour ajouter M_PIetc. Ce n'est PAS le cas avec cmath. Vous devez donc vous assurer #define _USE_MATH_DEFINESavant d'inclure quoi que ce soit d'autre. J'espère que cela clarifie les choses pour vous :)

À défaut d'inclure simplement, math.hvous utilisez du C / C ++ non standard comme déjà indiqué :)

Edit 2 : Ou comme David le souligne dans les commentaires, créez-vous une constante qui définit la valeur et vous avez de toute façon quelque chose de plus portable :)

Goz
la source
L'ayant défini auparavant, stdafx.hc'est le problème des OP que j'ai déjà rencontré ce comportement.
Alok Save le
@Als: Non, ce n'est pas ça ... je l'ai craqué et expliqué dans ma modification ci-dessus :)
Goz
Eh bien, c'était la première chose à faire, gardez-la au-dessus de tous les autres heasders. J'ai demandé à l'OP de faire de même .... Quoi qu'il en soit, ma réponse supprimera ma réponse car votre réponse indique la raison réelle pour laquelle elle devrait être avant les en-têtes standard.
Alok Enregistrer le
3
Vous obtiendrez ce comportement, par exemple, si quelque chose d'autre arrivait à #include <math.h> avant vous. Cela dit, il n'y a rien dans la norme qui dit que <cmath> doit inclure <math.h>, ou qu'il doit activer les définitions non standard dans <math.h>. Malheureusement, M_PI n'est pas standard. Pour la portabilité, la meilleure chose à faire est de la définir vous-même. Mieux encore, faites-en une valeur const static doubleplutôt qu'une # valeur définie.
David Hammen
1
@David Hammen: D'accord ... le définir vous-même est certainement l'option la plus portable :)
Goz
14

Pensez à ajouter le commutateur / D_USE_MATH_DEFINES à votre ligne de commande de compilation ou à définir la macro dans les paramètres du projet. Cela fera glisser le symbole vers tous les coins sombres accessibles des fichiers d'inclusion et source, laissant votre source propre pour plusieurs plates-formes. Si vous le définissez globalement pour l'ensemble du projet, vous ne l'oublierez pas plus tard dans un ou plusieurs nouveaux fichiers.

Thinkeye
la source
C'est probablement une bonne réponse lorsque vous utilisez VisualStudio, mais notez que cela n'a pas résolu le problème pour moi lors de la compilation via la ligne de commande Matlab mex (que j'ai utilisée mex -D_USE_MATH_DEFINES). L'ajout de /Y-smewhere dans certains fichiers mexoptions Matlab a aidé ...
aka.nice
9

Cela fonctionne pour moi:

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

using namespace std;

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

    return 0;
}

Compile et estampes picomme I devraient: cl /O2 main.cpp /link /out:test.exe.

Il doit y avoir une incompatibilité entre le code que vous avez publié et celui que vous essayez de compiler.

Assurez-vous qu'aucun en-tête précompilé n'est extrait avant votre fichier #define.

rubenvb
la source
Quelle version de VisualStudio utilisez-vous?
Goz le
Le même programme a bien fonctionné pour moi en utilisant le compilateur de ligne de commande de Visual C ++ 2010 Express Edition. La seule différence est que j'ai utilisé std :: printf () de <cstdio> au lieu de std :: cout de <iostream>.
4
Oui, je l'ai compris ... c'est parce que maths.h est appelé depuis les gardes d'en-tête de cmath ... donc maths.h a déjà été inclus à partir d'un en-tête précédent sans l'ensemble #define :)
Goz
4

C'est toujours un problème dans VS Community 2015 et 2017 lors de la création d'applications console ou Windows. Si le projet est créé avec des en-têtes précompilés, les en-têtes précompilés sont apparemment chargés avant l' un des #includes, donc même si le #define _USE_MATH_DEFINES est la première ligne, il ne sera pas compilé. #incluant math.h au lieu de cmath ne fait aucune différence.

Les seules solutions que je peux trouver sont soit de partir d'un projet vide (pour une console simple ou des applications système embarquées), soit d'ajouter / Y- aux arguments de la ligne de commande, ce qui désactive le chargement des en-têtes précompilés.

Pour plus d'informations sur la désactivation des en-têtes précompilés, voir par exemple https://msdn.microsoft.com/en-us/library/1hy7a92h.aspx

Ce serait bien que MS modifie / corrige cela. J'enseigne des cours d'introduction à la programmation dans une grande université, et expliquer cela aux débutants ne se résume jamais tant qu'ils n'ont pas commis l'erreur et se sont débattus avec elle pendant environ un après-midi.

user3533658
la source
Je confirme que le piratage / Y- a fonctionné pour moi, pour le code C #include <math.h>
aka.nice
1
Ce n'est pas du tout un problème dans VS. _USE_MATH_DEFINESdoit être défini avant d'inclure des en-têtes. Généralement via les paramètres du projet ou via l'en-tête de configuration. Il est faux de supposer que le simple fait de le mettre à la première ligne entraînera sa définition avant tous les en-têtes.
user7860670
1

Selon la documentation Microsoft sur les constantes mathématiques :

Le fichier ATLComTime.hinclut math.hlorsque votre projet est construit en mode Release. Si vous utilisez une ou plusieurs constantes mathématiques dans un projet qui inclut également ATLComTime.h, vous devez définir _USE_MATH_DEFINESavant d'inclure ATLComTime.h.

Le fichier ATLComTime.hpeut être inclus indirectement dans votre projet. Dans mon cas, un ordre possible d'inclusion était le suivant:

du projet "stdafx.h"<afxdtctl.h><afxdisp.h><ATLComTime.h><math.h>

αλεχολυτ
la source
Cela peut expliquer pourquoi / Y- (désactiver stdafx.h) résoudrait le problème, mais il reste à expliquer pourquoi fournir -D_USE_MATH_DEFINESdans les paramètres par défaut du compilateur ne suffit pas pour résoudre le problème ... Puisque la compilation s'est faite via la commande Matlab mex pour la mienne problème, ce n'est pas si évident de suivre ...
aka.nice
0

Comme suggéré par user7860670, cliquez avec le bouton droit sur le projet, sélectionnez les propriétés, accédez à C / C ++ -> Préprocesseur et ajoutez _USE_MATH_DEFINESaux définitions de préprocesseur.

C'est ce qui a fonctionné pour moi.

Den-Jason
la source
0

Avec CMake, ce serait juste

add_compile_definitions(_USE_MATH_DEFINES)

dans CMakeLists.txt.

FLUXparticule
la source