M_PI hoạt động với math.h nhưng không hoạt động với cmath trong Visual Studio


94

Tôi đang sử dụng Visual Studio 2010. Tôi đã đọc rằng trong C ++ thì tốt hơn là nên sử dụng <cmath>hơn là <math.h>.

Nhưng trong chương trình tôi đang cố gắng viết (ứng dụng bảng điều khiển Win32, dự án trống) nếu tôi viết:

#define _USE_MATH_DEFINES
#include <math.h>

nó biên dịch, trong khi nếu tôi viết

#define _USE_MATH_DEFINES
#include <cmath>

nó không thành công với

lỗi C2065: 'M_PI': mã định danh không được khai báo

Nó có bình thường không? Có vấn đề gì không nếu tôi sử dụng cmath hoặc math.h? Nếu có, làm thế nào tôi có thể làm cho nó hoạt động với cmath?

CẬP NHẬT : nếu tôi xác định _USE_MATH_DEFINES trong GUI, nó sẽ hoạt động. Bất kỳ manh mối tại sao điều này đang xảy ra?


Các tệp nguồn của bạn là .c hay .cpp?
Thụy Sĩ

1
Thụy Sĩ: không nên quan trọng ở đây.
rubenvb

Rất lạ ... Tôi có thể xác nhận rằng tôi gặp vấn đề tương tự với VS2010 ... tôi đang tìm hiểu điều gì đang ngăn định nghĩa vượt qua ... nó phải được hoàn tác ở đâu đó ... nhưng tôi không thể tìm ra nơi
Goz

Với x86, nó sẽ phàn nàn lỗi C2065. Với x64, sau đó không có lỗi.
user2616989

Câu trả lời:


116

Điều thú vị là tôi đã kiểm tra điều này trên một ứng dụng của mình và tôi gặp lỗi tương tự.

Tôi đã dành một thời gian để kiểm tra các tiêu đề để xem liệu có bất cứ điều gì không xác định được _USE_MATH_DEFINESvà không tìm thấy gì.

Vì vậy, tôi đã di chuyển

#define _USE_MATH_DEFINES
#include <cmath>

là thứ đầu tiên trong tệp của tôi (tôi không sử dụng PCH nên nếu bạn là bạn, bạn sẽ phải có nó sau #include "stdafx.h") và đột nhiên nó biên dịch hoàn hảo.

Hãy thử di chuyển nó lên cao hơn trên trang. Hoàn toàn không chắc chắn về lý do tại sao điều này sẽ gây ra vấn đề.

Chỉnh sửa : Đã tìm ra. Điều #include <math.h>này xảy ra trong các bảo vệ tiêu đề của cmath. Điều này có nghĩa là một cái gì đó cao hơn trong danh sách #includes được bao gồm cmathmà không #defineđược chỉ định. math.hđược thiết kế đặc biệt để bạn có thể bao gồm lại nó với định nghĩa hiện đã được thay đổi thành thêm, M_PIv.v. Đây KHÔNG phải là trường hợp với cmath. Vì vậy, bạn cần chắc chắn rằng bạn #define _USE_MATH_DEFINEStrước khi thêm bất cứ thứ gì khác. Hy vọng rằng nó rõ ràng cho bạn :)

Không chỉ bao gồm math.hbạn đang sử dụng C / C ++ không chuẩn như đã chỉ ra :)

Chỉnh sửa 2 : Hoặc như David đã chỉ ra trong các nhận xét chỉ cần tạo cho bạn một hằng số xác định giá trị và dù sao thì bạn cũng có một cái gì đó dễ di chuyển hơn :)


Đã xác định nó trước đây stdafx.hlà vấn đề OPs mà tôi đã đối mặt với hành vi này trước đây.
Alok Save

@Als: Không phải vậy đâu ... đã bẻ khóa nó và giải thích trong phần chỉnh sửa của tôi ở trên :)
Goz

Đó là điều đầu tiên phải làm, giữ nó trên tất cả các heasder khác mà tôi đã yêu cầu OP làm tương tự .... Nhưng dù sao thì sẽ xóa câu trả lời của tôi vì câu trả lời của bạn cho biết lý do thực sự tại sao nó phải có trước tiêu đề chuẩn.
Alok Save

3
Bạn sẽ nhận được hành vi này, ví dụ: nếu điều gì đó khác đã xảy ra với #include <math.h> trước khi bạn thực hiện. Điều đó nói rằng, không có gì trong tiêu chuẩn nói rằng <cmath> phải bao gồm <math.h>, hoặc nó phải kích hoạt các định nghĩa không chuẩn trong <math.h>. Thật không may, M_PI không phải là tiêu chuẩn. Đối với tính di động, điều tốt nhất cần làm là tự xác định nó. Tốt hơn, hãy đặt nó const static doublethành một giá trị thay vì # được xác định.
David Hammen

1
@David Hammen: Đồng ý .. tự xác định nó chắc chắn là lựa chọn di động nhất :)
Goz

14

Xem xét thêm công tắc / D_USE_MATH_DEFINES vào dòng lệnh biên dịch của bạn hoặc để xác định macro trong cài đặt dự án. Thao tác này sẽ kéo biểu tượng đến tất cả các góc tối có thể tiếp cận của tệp bao gồm và tệp nguồn, giúp nguồn của bạn sạch sẽ cho nhiều nền tảng. Nếu bạn đặt nó trên toàn cầu cho toàn bộ dự án, bạn sẽ không quên nó sau này trong (các) tệp mới.


Đó có thể là một câu trả lời tốt khi hoạt động từ VisualStudio, nhưng lưu ý rằng nó không giải quyết được vấn đề cho tôi khi biên dịch thông qua dòng lệnh Matlab mex (tôi đã sử dụng mex -D_USE_MATH_DEFINES). Chỉ thêm /Y-smewhere trong một số tập tin mexoptions Matlab đã giúp ...
aka.nice

9

Điều này phù hợp với tôi:

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

using namespace std;

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

    return 0;
}

Biên dịch và in pinhư là nên: cl /O2 main.cpp /link /out:test.exe.

Phải có sự không khớp trong mã bạn đã đăng và mã bạn đang cố gắng biên dịch.

Hãy chắc chắn rằng không có tiêu đề được biên dịch trước nào được đưa vào trước của bạn #define.


Bạn đang sử dụng phiên bản VisualStudio nào?
Goz

Chương trình tương tự hoạt động tốt đối với tôi khi sử dụng trình biên dịch dòng lệnh của Visual C ++ 2010 Express Edition. Sự khác biệt duy nhất là tôi đã sử dụng std :: printf () từ <cstdio> thay vì std :: cout từ <iostream>.

4
Vâng I figured it out ... vì maths.h của nó được gọi từ bên trong bảo vệ tiêu đề cmath của ... do đó maths.h đã được đưa từ một tiêu đề trước đó mà không cần tập #define :)
Goz

4

Đây vẫn là một vấn đề trong VS Community 2015 và 2017 khi xây dựng ứng dụng console hoặc windows. Nếu dự án được tạo với các tiêu đề được biên dịch trước, thì các tiêu đề được biên dịch trước dường như được tải trước bất kỳ #includes nào, vì vậy ngay cả khi #define _USE_MATH_DEFINES là dòng đầu tiên, nó sẽ không được biên dịch. #including math.h thay vì cmath không tạo ra sự khác biệt.

Các giải pháp duy nhất tôi có thể tìm thấy là bắt đầu từ một dự án trống (đối với bảng điều khiển đơn giản hoặc ứng dụng hệ thống nhúng) hoặc thêm / Y- vào các đối số dòng lệnh, điều này sẽ tắt việc tải các tiêu đề được biên dịch trước.

Để biết thông tin về cách tắt tiêu đề được biên dịch sẵn, hãy xem ví dụ https://msdn.microsoft.com/en-us/library/1hy7a92h.aspx

Sẽ rất tốt nếu MS thay đổi / sửa lỗi này. Tôi dạy các khóa học lập trình nhập môn tại một trường đại học lớn và giải thích điều này cho những người mới không bao giờ chìm đắm cho đến khi họ mắc lỗi và vật lộn với nó trong một buổi chiều hoặc lâu hơn.


tôi xác nhận rằng hacking / Y- đã hoạt động với tôi, đối với mã C #include <math.h>
aka.nice

1
Đây không phải là một vấn đề trong VS cả. _USE_MATH_DEFINESnên được xác định trước khi đưa vào bất kỳ tiêu đề nào. Thông thường hoặc thông qua thiết lập dự án hoặc thông qua tiêu đề cấu hình. Sai lầm khi cho rằng chỉ cần đặt nó ở dòng đầu tiên sẽ khiến nó được xác định trước tất cả các tiêu đề.
user7860670

1

Theo tài liệu của Microsoft về Hằng số Toán học :

Tệp ATLComTime.hbao gồm math.hthời điểm dự án của bạn được tạo ở chế độ Phát hành. Nếu bạn sử dụng một hoặc nhiều hằng số toán học trong một dự án cũng bao gồm ATLComTime.h, bạn phải xác định _USE_MATH_DEFINEStrước khi đưa vào ATLComTime.h.

Tệp ATLComTime.hcó thể được bao gồm gián tiếp trong dự án của bạn. Trong trường hợp của tôi, có thể có một thứ tự bao gồm như sau:

của dự án "stdafx.h"<afxdtctl.h><afxdisp.h><ATLComTime.h><math.h>


Điều này có thể giải thích tại sao / Y- (vô hiệu hóa stdafx.h) sẽ giải quyết được vấn đề, tuy nhiên nó vẫn phải giải thích tại sao việc cung cấp -D_USE_MATH_DEFINEStrong cài đặt trình biên dịch mặc định không đủ để giải quyết vấn đề ... Vì việc biên dịch thông qua lệnh Matlab mex cho riêng tôi vấn đề, nó không phải là rõ ràng để theo dõi ...
aka.nice

0

Theo đề xuất của user7860670, nhấp chuột phải vào dự án, chọn thuộc tính, điều hướng đến C / C ++ -> Preprocessor và thêm _USE_MATH_DEFINESvào Định nghĩa tiền xử lý.

Đó là những gì đã làm việc cho tôi.


0

Với CMake nó sẽ chỉ là

add_compile_definitions(_USE_MATH_DEFINES)

trong CMakeLists.txt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.