M_PI работает с math.h, но не с cmath в Visual Studio
Я использую Visual Studio 2010. Я прочитал, что в С++ лучше использовать <cmath>
, а не <math.h>
.
Но в программе я пытаюсь написать (консольное приложение Win32, пустой проект), если я пишу:
#define _USE_MATH_DEFINES
#include <math.h>
он компилируется, а если я пишу
#define _USE_MATH_DEFINES
#include <cmath>
он терпит неудачу с
ошибка C2065: "M_PI": необъявленный идентификатор
Это нормально? Это имеет значение, если я использую cmath или math.h? Если да, как я могу заставить его работать с cmath?
UPDATE: если я определяю _USE_MATH_DEFINES в графическом интерфейсе, он работает. Есть ли подсказки, почему это происходит?
Ответы
Ответ 1
Интересно, что я проверил это на своем приложении и получил ту же ошибку.
Я потратил некоторое время, проверяя заголовки, чтобы увидеть, нет ли чего-то, что не было бы отключено _USE_MATH_DEFINES и ничего не найдено.
Итак, я переместил
#define _USE_MATH_DEFINES
#include <cmath>
чтобы быть первым делом в моем файле (я не использую PCH, поэтому, если вам это нужно, вам придется иметь его после #include "stdafx.h" ), и вдруг он скомпилируется отлично.
Попробуйте переместить его вверх по странице. Полностью не уверен, почему это может вызвать проблемы.
Изменить. Выяснилось. #include встречается в защитных оболочках cmath. Это означает, что что-то выше в списке #includes включает cmath без указанного #define. math.h специально разработан так, что вы можете включить его снова с тем определением, которое теперь изменилось, чтобы добавить M_PI и т.д. Это не так с cmath. Поэтому вам нужно убедиться, что вы #define _USE_MATH_DEFINES, прежде чем включать что-либо еще. Надеюсь, что это очистит для вас:)
В противном случае просто включите math.h, вы используете нестандартный C/С++, как уже указывалось:)
Изменить 2. Или, как указывает Дэвид в комментариях, просто сделайте себе константу, которая определяет значение, и у вас есть что-то более портативное в любом случае:)
Ответ 2
Рассмотрите возможность добавления переключателя /D _USE_MATH_DEFINES в командную строку компиляции или для определения макроса в настройках проекта. Это перетащит символ во все доступные темные углы файлов include и source, оставляя ваш источник чистым для нескольких платформ. Если вы установите его глобально для всего проекта, вы не забудете его позже в новом файле.
Ответ 3
Это работает для меня:
#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
нет предварительно скомпилированных заголовков.
Ответ 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 изменила/исправила это. Я преподаю вводные курсы программирования в большом университете, и объясняя это, новички никогда не погружаются, пока они не совершили ошибку и не боролись с ней на второй день или около того.