114 votes

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

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 que j'essaie 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>

il échoue avec

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

Est-ce normal ? Est-ce que cela a de l'importance si j'utilise cmath ou math.h ? Si oui, comment puis-je le faire fonctionner avec cmath ?

UPDATE Si je définis _USE_MATH_DEFINES dans l'interface graphique, cela fonctionne. Avez-vous une idée de la raison pour laquelle cela se produit ?

0 votes

Vos fichiers sources sont-ils .c ou .cpp ?

1 votes

Suisse : cela ne devrait pas avoir d'importance ici.

0 votes

Très étrange... Je peux confirmer que j'ai le même problème avec VS2010 ... je cherche ce qui empêche la définition de passer ... il doit être undef'd quelque part ... mais je n'arrive pas à trouver où.

141voto

Goz Points 35007

Il est intéressant de noter que j'ai vérifié cela sur une de mes applications et j'ai obtenu 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'undef'ing dans les _USE_MATH_DEFINES et n'a rien trouvé.

Donc j'ai déplacé le

#define _USE_MATH_DEFINES
#include <cmath>

pour être la première chose dans mon dossier (je n'utilise pas de PCH, donc si vous le faites, vous devrez l'avoir après les #include "stdafx.h" ) et soudain, il compile parfaitement.

Essayez de le déplacer plus haut sur la page. Je ne vois pas du tout pourquoi cela poserait problème.

Modifier : J'ai compris. Le site #include <math.h> se produit dans les gardes de l'en-tête de cmath. Cela signifie que quelque chose de plus haut dans la liste des #includes inclut cmath sans le #define spécifié. math.h est spécifiquement conçu pour que vous puissiez l'inclure à nouveau avec cette définition maintenant modifiée pour ajouter M_PI etc. Ce n'est PAS le cas avec cmath . Vous devez donc vous assurer que vous #define _USE_MATH_DEFINES avant d'inclure quoi que ce soit d'autre. J'espère que cela vous a éclairci la situation :)

A défaut, il suffit d'inclure math.h vous utilisez un C/C++ non standard comme cela a déjà été souligné :)

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

0 votes

L'ayant défini auparavant stdafx.h est le problème du PO, j'ai déjà été confronté à ce comportement.

0 votes

@Als : Nah its not that ... have cracked it and explained in my edit above :)

0 votes

Eh bien, c'était la première chose à faire, le garder au-dessus de tous les autres collecteurs. J'ai demandé au PO de faire la même chose..... Je vais supprimer ma réponse puisque votre réponse dit la raison réelle pour laquelle il devrait être avant les collecteurs standard.

18voto

Thinkeye Points 93

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 dans tous les coins sombres accessibles des fichiers include et source, laissant votre source propre pour de multiples plateformes. Si vous le définissez globalement pour l'ensemble du projet, vous ne l'oublierez pas plus tard dans un ou plusieurs nouveaux fichiers.

0 votes

C'est probablement une bonne réponse lorsque l'on opère à partir de VisualStudio, mais notez que cela n'a pas résolu le problème pour moi lorsque j'ai compilé par la ligne de commande Matlab mex (j'ai utilisé mex -D_USE_MATH_DEFINES ). Il suffit d'ajouter /Y- n'importe où dans un fichier de mexoptions de Matlab a aidé...

12voto

rubenvb Points 27271

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 imprime pi comme il se doit : cl /O2 main.cpp /link /out:test.exe .

Il doit y avoir un décalage entre le code que vous avez posté et celui que vous essayez de compiler.

Assurez-vous qu'il n'y a pas d'en-têtes précompilés qui sont tirés avant votre #define .

0 votes

Quelle version de VisualStudio utilisez-vous ?

0 votes

Le même programme a bien fonctionné pour moi en utilisant le compilateur en 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>.

5 votes

Oui, j'ai compris ... c'est parce que maths.h est appelé à partir des gardes de l'en-tête de cmath ... donc maths.h a déjà été inclus à partir d'un en-tête précédent sans le #define :)

6voto

user3533658 Points 51

Ce problème persiste dans VS Community 2015 et 2017 lors de la création d'applications pour la console ou pour Windows. Si le projet est créé avec des en-têtes précompilés, ces derniers 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 compilera pas. #inclure math.h au lieu de cmath ne fait pas de différence.

Les seules solutions que j'ai pu trouver sont soit de démarrer à partir d'un projet vide (pour les applications simples de type console ou système embarqué), 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 des 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 change/répare cela. J'enseigne des cours d'introduction à la programmation dans une grande université, et expliquer cela aux débutants n'est jamais compris tant qu'ils n'ont pas fait l'erreur et ne se sont pas débattus avec elle pendant une après-midi ou plus.

0 votes

Je confirme que le hacking /Y- a fonctionné pour moi, pour le code C #include <math.h>

1 votes

Ce n'est pas du tout un problème dans VS. _USE_MATH_DEFINES doit être défini avant d'inclure les en-têtes. Généralement, il s'agit d'un paramètre du projet ou d'un en-tête de configuration. Il est erroné de supposer que le simple fait de le mettre à la première ligne fera en sorte qu'il sera défini avant tous les en-têtes.

6voto

FLUXparticle Points 81

Avec CMake, ce serait juste

add_compile_definitions(_USE_MATH_DEFINES)

sur CMakeLists.txt .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X