M_PI працює з math.h, але не з cmath у Visual Studio


94

Я використовую Visual Studio 2010. Я читав, що в C ++ краще використовувати, <cmath>а не <math.h>.

Але в програмі я намагаюся написати (консольний додаток Win32, порожній проект), якщо пишу:

#define _USE_MATH_DEFINES
#include <math.h>

він компілюється, тоді як якщо я пишу

#define _USE_MATH_DEFINES
#include <cmath>

це не вдається з

помилка C2065: 'M_PI': незадекларований ідентифікатор

Це нормально? Чи має значення, чи використовую я cmath або math.h? Якщо так, як я можу змусити це працювати з cmath?

ОНОВЛЕННЯ : якщо я визначаю _USE_MATH_DEFINES у графічному інтерфейсі, це працює. Будь-яка підказка, чому це відбувається?


Ваші вихідні файли .c або .cpp?
Швейцарія

1
Швейцарець: тут не має значення.
rubenvb

Дуже дивно ... Я можу підтвердити, що отримую ту саму проблему з VS2010 ... розглядаю, що перешкоджає проходженню дефініції ... це десь має бути не визначено ... але я не можу зрозуміти, де
Goz

З x86 він скаржиться на помилку C2065. З x64 помилок немає.
user2616989

Відповіді:


116

Цікаво, що я перевірив це у своєму додатку і отримав ту ж помилку.

Я витратив якийсь час, перевіряючи заголовки, щоб побачити, чи не було чогось із дефіцитом _USE_MATH_DEFINESі нічого не знайшов.

Тож я перемістив

#define _USE_MATH_DEFINES
#include <cmath>

бути першим у моєму файлі (я не використовую PCH, тому, якщо ви є, вам доведеться мати його після #include "stdafx.h"), і раптом він ідеально скомпілюється.

Спробуйте перемістити його вище по сторінці. Зовсім невпевнений, чому це може спричинити проблеми.

Редагувати : зрозумів. Це #include <math.h>відбувається в межах заголовків заголовків cmath. Це означає, що щось вище в списку #includes включає cmathбез #defineвказаного. math.hспеціально розроблений для того, щоб ви могли знову включити його до того, що дефініція тепер змінена на додавання M_PIтощо cmath. Тому вам потрібно переконатися, що ви, #define _USE_MATH_DEFINESперш ніж включити щось інше. Сподіваюся, це прояснить для вас :)

Якщо не вдасться просто включити, math.hви використовуєте нестандартний C / C ++, як уже зазначалося :)

Редагування 2 : Або, як зазначає Девід у коментарях, просто зробіть собі константу, яка визначає цінність, і у вас все одно є щось більш портативне :)


Визначивши це раніше, stdafx.hце проблема OP, з якою я стикався раніше.
Alok Save

@Als: Ні, це не те ... зламали це і пояснили в моїй редакції вище :)
Goz

Ну, це було перше, що слід зробити, дотримуйтесь його над усіма іншими обробниками. Я попросив OP зробити те саме .... У будь-якому випадку моя відповідь буде видалена, оскільки ваша відповідь говорить про фактичну причину, чому вона повинна бути перед стандартними заголовками.
Алок Зберегти

3
Ви отримаєте таку поведінку, наприклад, якби щось інше сталося з #include <math.h> до того, як ви це зробите. Тим не менш, у стандарті немає нічого, що говорить, що <cmath> має включати <math.h> або що він повинен увімкнути нестандартні визначення в <math.h>. На жаль, M_PI нестандартний. Для мобільності найкраще визначити це самостійно. А ще краще, зробіть це, const static doubleа не значення #defined.
Девід Хаммен,

1
@David Hammen: Погоджено .. визначити це самостійно, безумовно, є найбільш портативним варіантом :)
Goz

14

Подумайте про додавання перемикача / D_USE_MATH_DEFINES до вашого командного рядка компіляції або для визначення макросу в налаштуваннях проекту. Це перетягне символ у всі доступні темні кути файлів включення та джерела, залишаючи джерело чистим для декількох платформ. Якщо ви встановите його глобально для всього проекту, ви не забудете про це згодом у новому файлі (файлах).


Це, мабуть, хороша відповідь під час роботи з VisualStudio, але зауважте, що це не вирішило проблему для мене під час компіляції через командний рядок Matlab mex (я використовував mex -D_USE_MATH_DEFINES). /Y-Допомогло лише додавання smewhere до якогось файлу mexoptions Matlab ...
aka.nice

9

Це працює для мене:

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

using namespace std;

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

    return 0;
}

Збирає і друкує piподібне, слід: cl /O2 main.cpp /link /out:test.exe.

У коді, який ви опублікували, і коді, який ви намагаєтеся скомпілювати, має бути невідповідність.

Переконайтеся, що до вашого попередньо не скомпільовані заголовки втягуються #define.


Яку версію VisualStudio ви використовуєте?
Goz

Ця ж програма добре працювала для мене, використовуючи компілятор командного рядка Visual C ++ 2010 Express Edition. Єдина відмінність полягає в тому, що я використовував std :: printf () з <cstdio> замість std :: cout з <iostream>.

4
Так, я розібрався ... це тому, що maths.h викликається зсередини захисників заголовків cmath ... так maths.h вже включено з попереднього заголовка без #define набору :)
Goz

4

Це все ще залишається проблемою у VS Community 2015 та 2017 при створенні консольних або віконних програм. Якщо проект створюється із заздалегідь скомпільованими заголовками, попередньо скомпільовані заголовки, мабуть, завантажуються перед будь-яким з #includes, тому навіть якщо #define _USE_MATH_DEFINES є першим рядком, він не компілюється. #including math.h замість cmath не має значення.

Єдині рішення, які я можу знайти, - це почати з порожнього проекту (для простої консолі або вбудованих системних програм) або додати / Y- до аргументів командного рядка, що вимикає завантаження попередньо скомпільованих заголовків.

Інформацію про вимкнення попередньо скомпільованих заголовків див., Наприклад, https://msdn.microsoft.com/en-us/library/1hy7a92h.aspx

Було б непогано, якби MS змінила / виправила це. Я викладаю вступні курси програмування у великому університеті, і пояснення цього новачкам ніколи не занурюється, поки вони не допустили помилки і не боролися з нею протягом півдня.


я підтверджую, що злом / Y- працював у мене, для коду C #include <math.h>
aka.nice

1
У VS це не проблема. _USE_MATH_DEFINESслід визначити перед включенням будь-яких заголовків. Зазвичай або через налаштування проекту, або через заголовок конфігурації. Неправильно вважати, що просто розміщення його в першому рядку спричинить його визначення перед усіма заголовками.
user7860670

1

Відповідно до документації Microsoft про математичні константи :

Файл ATLComTime.hвключає, math.hколи ваш проект будується в режимі випуску. Якщо ви використовуєте одну або кілька математичних констант у проекті, який також включає ATLComTime.h, _USE_MATH_DEFINESперед включенням потрібно визначитись ATLComTime.h.

Файл ATLComTime.hможе бути включений опосередковано до вашого проекту. У моєму випадку одним із можливих порядків включення було таке:

проект "stdafx.h"<afxdtctl.h><afxdisp.h><ATLComTime.h>→ →<math.h>


Це може пояснити, чому / Y- (вимкнути stdafx.h) вирішить проблему, однак залишається пояснити, чому надання -D_USE_MATH_DEFINESналаштувань компілятора за замовчуванням недостатньо для вирішення проблеми ... Оскільки компіляція була власною командою Matlab mex проблема, це не так очевидно для відстеження ...
aka.nice

0

Як запропоновано користувачем7860670, клацніть правою кнопкою миші на проекті, виберіть властивості, перейдіть до C / C ++ -> Preprocessor та додайте _USE_MATH_DEFINESдо Preprocessor Definitions.

Це те, що мені вдалося.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.