M_PI ทำงานร่วมกับ math.h แต่ไม่ใช่กับ cmath ใน Visual Studio


96

ฉันกำลังใช้ 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 ได้อย่างไร?

UPDATE : ถ้าฉันกำหนด _USE_MATH_DEFINES ใน GUI มันก็ใช้ได้ มีเงื่อนงำอะไรที่เกิดขึ้น?


ไฟล์ต้นฉบับของคุณเป็น. c หรือ. cpp?
สวิส

1
สวิส: ไม่ควรสำคัญที่นี่
rubenvb

แปลกมาก ... ฉันสามารถยืนยันได้ว่าฉันได้รับปัญหาเดียวกันกับ VS2010 ... กำลังตรวจสอบว่าอะไรคือสิ่งที่หยุดการกำหนดผ่าน ... มันจะต้องไม่ได้อยู่ที่ไหนสักแห่ง ... แต่ฉันคิดไม่ออกว่า
Goz

ด้วย x86 มันจะบ่นข้อผิดพลาด C2065 ด้วย x64 ไม่มีข้อผิดพลาด
user2616989

คำตอบ:


117

ที่น่าสนใจฉันตรวจสอบสิ่งนี้ในแอพของฉันและฉันก็ได้รับข้อผิดพลาดเดียวกัน

ฉันใช้เวลาสักพักในการตรวจสอบส่วนหัวเพื่อดูว่ามีอะไรที่ไม่สามารถระบุได้_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คือปัญหา OPs ที่ฉันเคยเผชิญกับพฤติกรรมนี้มาก่อน
Alok Save

@Als: ไม่ว่า ... ได้แตกมันและอธิบายในการแก้ไขของฉันด้านบน :)
Goz

นั่นเป็นสิ่งแรกที่ต้องทำเก็บไว้เหนือ heasders อื่น ๆ ที่ฉันขอให้ OP ทำเช่นเดียวกัน .... อย่างไรก็ตามจะลบคำตอบของฉันเนื่องจากคำตอบของคุณบอกเหตุผลที่แท้จริงว่าทำไมจึงควรอยู่ก่อนส่วนหัวมาตรฐาน
Alok Save

3
คุณจะได้รับพฤติกรรมนี้ตัวอย่างเช่นหากมีสิ่งอื่นเกิดขึ้นกับ #include <math.h> ก่อนที่คุณจะทำ ที่กล่าวว่าไม่มีอะไรในมาตรฐานที่ระบุว่า <cmath> ต้องรวม <math.h> หรือต้องเปิดใช้งานคำจำกัดความที่ไม่เป็นมาตรฐานใน <math.h> ขออภัย M_PI ไม่ได้มาตรฐาน สำหรับการพกพาสิ่งที่ดีที่สุดที่ต้องทำคือกำหนดเอง ยังดีกว่าให้const static doubleเป็นค่าที่กำหนดไว้มากกว่า # กำหนด
David Hammen

1
@David Hammen: ตกลง .. การกำหนดตัวเองเป็นตัวเลือกที่พกพาสะดวกที่สุด :)
Goz

14

พิจารณาเพิ่มสวิตช์ / D_USE_MATH_DEFINES ในบรรทัดคำสั่งคอมไพล์ของคุณหรือกำหนดมาโครในการตั้งค่าโปรเจ็กต์ สิ่งนี้จะลากสัญลักษณ์ไปยังมุมมืดที่เข้าถึงได้ทั้งหมดของไฟล์รวมและไฟล์ต้นทางโดยปล่อยให้แหล่งที่มาของคุณสะอาดสำหรับหลายแพลตฟอร์ม หากคุณตั้งค่าทั่วโลกสำหรับทั้งโปรเจ็กต์คุณจะไม่ลืมมันในภายหลังในไฟล์ใหม่


อาจเป็นคำตอบที่ดีเมื่อใช้งานจาก VisualStudio แต่โปรดทราบว่ามันไม่สามารถแก้ปัญหาให้ฉันได้เมื่อรวบรวมผ่านบรรทัดคำสั่ง Matlab mex (ฉันใช้mex -D_USE_MATH_DEFINES) เฉพาะการเพิ่ม/Y-smewhere ในไฟล์ mexoptions ของ Matlab เท่านั้นที่ช่วยได้ ...
aka.nice

10

สิ่งนี้ใช้ได้กับฉัน:

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

using namespace std;

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

    return 0;
}

รวบรวมและพิมพ์เช่นมีที่ควร:picl /O2 main.cpp /link /out:test.exe

ต้องมีโค้ดที่คุณโพสต์ไม่ตรงกันและโค้ดที่คุณพยายามรวบรวม

ตรวจสอบให้แน่ใจว่าไม่มีการดึงส่วนหัวที่คอมไพล์ไว้ก่อนหน้า#defineไฟล์.


คุณใช้ VisualStudio เวอร์ชันใด
Goz

โปรแกรมเดียวกันทำงานได้ดีสำหรับฉันโดยใช้คอมไพเลอร์บรรทัดคำสั่งของ Visual C ++ 2010 Express Edition ข้อแตกต่างเพียงอย่างเดียวคือฉันใช้ std :: printf () จาก <cstdio> แทน std :: cout จาก <iostream>

5
ใช่ฉันคิดออกแล้ว ... เป็นเพราะ maths.h ถูกเรียกจากภายใน header guards ของ cmath ... ดังนั้น maths.h จึงถูกรวมไว้แล้วจากส่วนหัวก่อนหน้านี้โดยไม่ต้องตั้งค่า #define :)
Goz

4

ปัญหานี้ยังคงเป็นปัญหาใน VS Community 2015 และ 2017 เมื่อสร้างแอปคอนโซลหรือ Windows ถ้าโปรเจ็กต์ถูกสร้างขึ้นโดยมีส่วนหัวที่คอมไพล์ไว้แล้วส่วนหัวที่คอมไพล์ไว้ล่วงหน้าจะถูกโหลดก่อน #includes ใด ๆ ดังนั้นแม้ว่า #define _USE_MATH_DEFINES จะเป็นบรรทัดแรก แต่ก็จะไม่คอมไพล์ # รวม 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 ++ -> ตัวประมวลผลล่วงหน้าและเพิ่ม _USE_MATH_DEFINESตัวประมวลผลล่วงหน้าในข้อกำหนดของตัวประมวลผลล่วงหน้า

นั่นคือสิ่งที่ได้ผลสำหรับฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.