M_PI bekerja dengan math.h tetapi tidak dengan cmath di Visual Studio

96

Saya menggunakan Visual Studio 2010. Saya telah membaca bahwa di C ++ lebih baik digunakan <cmath>daripada <math.h>.

Tetapi dalam program saya mencoba menulis (aplikasi konsol Win32, proyek kosong) jika saya menulis:

#define _USE_MATH_DEFINES
#include <math.h>

itu mengkompilasi, sementara jika saya menulis

#define _USE_MATH_DEFINES
#include <cmath>

itu gagal dengan

kesalahan C2065: 'M_PI': pengenal tidak dideklarasikan

Apakah ini normal? Apakah penting jika saya menggunakan cmath atau math.h? Jika ya, bagaimana cara membuatnya bekerja dengan cmath?

UPDATE : jika saya mendefinisikan _USE_MATH_DEFINES di GUI, ini berfungsi. Ada petunjuk mengapa ini terjadi?

hyperknot
sumber
Apakah file sumber Anda .c atau .cpp?
Swiss
1
Swiss: seharusnya tidak masalah di sini.
rubenvb
Sangat aneh ... Saya dapat mengonfirmasi bahwa saya mendapatkan masalah yang sama dengan VS2010 ... sedang mencari tahu apa yang menghentikan definisi yang melewati ... itu pasti undef'd di suatu tempat ... tetapi saya tidak tahu di mana
Goz
Dengan x86, akan ada keluhan error C2065. Dengan x64, maka tidak ada kesalahan.
pengguna2616989

Jawaban:

117

Menariknya saya memeriksa ini di aplikasi saya dan saya mendapat kesalahan yang sama.

Saya menghabiskan beberapa saat memeriksa header untuk melihat apakah ada sesuatu yang tidak sesuai _USE_MATH_DEFINESdan tidak menemukan apa pun.

Jadi saya memindahkan

#define _USE_MATH_DEFINES
#include <cmath>

menjadi hal pertama dalam file saya (saya tidak menggunakan PCH jadi jika Anda harus memilikinya setelahnya #include "stdafx.h") dan tiba-tiba kompilasi dengan sempurna.

Coba pindahkan lebih tinggi ke atas halaman. Benar-benar tidak yakin mengapa ini akan menyebabkan masalah.

Edit : Berhasil. Itu #include <math.h>terjadi dalam pelindung header cmath. Ini berarti bahwa sesuatu yang lebih tinggi dari daftar #includes termasuk cmathtanpa #defineditentukan. math.hdirancang khusus sehingga Anda dapat memasukkannya lagi dengan definisinya sekarang diubah menjadi tambah, M_PIdll. Ini BUKAN kasusnya cmath. Jadi, Anda perlu memastikan Anda #define _USE_MATH_DEFINESsebelum memasukkan yang lain. Harapan yang menyelesaikannya untuk Anda :)

Gagal yang hanya mencakup math.hAnda menggunakan C / C ++ non-standar seperti yang telah ditunjukkan :)

Sunting 2 : Atau seperti yang ditunjukkan David di komentar, buatlah diri Anda konstan yang menentukan nilainya dan Anda tetap memiliki sesuatu yang lebih portabel :)

Goz
sumber
Setelah mendefinisikannya sebelumnya stdafx.hadalah masalah OP yang pernah saya hadapi dengan perilaku ini sebelumnya.
Alok Save
@Als: Nah bukan itu ... sudah retak dan jelaskan di edit saya di atas :)
Goz
Itu adalah hal pertama yang harus dilakukan, pertahankan di atas semua heasders lain. Saya meminta OP untuk melakukan hal yang sama .... Bagaimanapun akan menghapus jawaban saya karena jawaban Anda mengatakan alasan sebenarnya mengapa itu harus sebelum header standar.
Alok Simpan
3
Anda akan mendapatkan perilaku ini, misalnya, jika terjadi sesuatu yang lain #include <math.h> sebelum Anda melakukannya. Meskipun demikian, tidak ada dalam standar yang mengatakan <cmath> harus menyertakan <math.h>, atau harus mengaktifkan definisi non-standar di <math.h>. Sayangnya, M_PI tidak standar. Untuk portabilitas, hal terbaik yang harus dilakukan adalah menentukannya sendiri. Lebih baik lagi, jadikan itu sebagai const static doublenilai daripada #defined.
David Hammen
1
@David Hammen: Setuju .. mendefinisikannya sendiri jelas merupakan opsi yang paling portabel :)
Goz
14

Pertimbangkan untuk menambahkan sakelar / D_USE_MATH_DEFINES ke baris perintah kompilasi Anda, atau untuk menentukan makro dalam pengaturan proyek. Ini akan menyeret simbol ke semua sudut gelap yang dapat dijangkau dari file penyertaan dan sumber sehingga sumber Anda bersih untuk berbagai platform. Jika Anda menyetelnya secara global untuk keseluruhan proyek, Anda tidak akan melupakannya nanti di file baru.

Thinkeye
sumber
Ini mungkin jawaban yang bagus saat beroperasi dari VisualStudio, tetapi perhatikan bahwa itu tidak menyelesaikan masalah bagi saya saat mengompilasi melalui baris perintah Matlab mex (saya gunakan mex -D_USE_MATH_DEFINES). Hanya menambahkan /Y-di suatu tempat di beberapa file mexoptions Matlab membantu ...
alias. Bagus
10

Ini bekerja untuk saya:

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

using namespace std;

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

    return 0;
}

Mengkompilasi dan cetakan piseperti yaitu harus: cl /O2 main.cpp /link /out:test.exe.

Harus ada ketidakcocokan kode yang telah Anda posting dan yang Anda coba kompilasi.

Pastikan tidak ada header yang telah dikompilasi yang ditarik sebelum Anda #define.

rubenvb.dll
sumber
Versi VisualStudio apa yang Anda gunakan?
Goz
Program yang sama bekerja dengan baik untuk saya menggunakan kompiler baris perintah Visual C ++ 2010 Express Edition. Satu-satunya perbedaan adalah saya menggunakan std :: printf () dari <cstdio> daripada std :: cout dari <iostream>.
5
Ya, saya mengetahuinya ... itu karena maths.h dipanggil dari dalam pelindung header cmath ... jadi maths.h telah disertakan dari header sebelumnya tanpa set #define :)
Goz
4

Ini masih menjadi masalah di VS Community 2015 dan 2017 saat membuat aplikasi konsol atau windows. Jika proyek dibuat dengan header yang telah dikompilasi, header yang telah dikompilasi tampaknya dimuat sebelum #includes yang mana pun, jadi meskipun #define _USE_MATH_DEFINES adalah baris pertama, itu tidak akan dikompilasi. #termasuk math.h bukannya cmath tidak membuat perbedaan.

Satu-satunya solusi yang dapat saya temukan adalah memulai dari proyek kosong (untuk konsol sederhana atau aplikasi sistem tersemat) atau menambahkan / Y- ke argumen baris perintah, yang mematikan pemuatan header yang telah dikompilasi sebelumnya.

Untuk informasi tentang menonaktifkan header yang telah dikompilasi, lihat misalnya https://msdn.microsoft.com/en-us/library/1hy7a92h.aspx

Alangkah baiknya jika MS akan mengubah / memperbaiki ini. Saya mengajar kursus pemrograman pengantar di universitas besar, dan menjelaskan hal ini kepada pemula tidak akan pernah meresap sampai mereka membuat kesalahan dan berjuang keras selama sekitar satu sore.

pengguna3533658
sumber
saya mengonfirmasi bahwa peretasan / Y- berhasil untuk saya, untuk kode C #include <math.h>
aka.nice
1
Ini sama sekali bukan masalah di VS. _USE_MATH_DEFINESharus ditentukan sebelum memasukkan header apa pun. Biasanya baik melalui pengaturan proyek atau melalui tajuk konfigurasi. Salah untuk mengasumsikan bahwa hanya dengan meletakkannya di baris pertama akan menyebabkannya didefinisikan sebelum semua header.
pengguna7860670
1

Menurut dokumentasi Microsoft tentang Konstanta Matematika :

File tersebut ATLComTime.hmenyertakan math.hsaat proyek Anda dibuat dalam mode Rilis. Jika Anda menggunakan satu atau lebih konstanta matematika dalam sebuah proyek yang juga termasuk ATLComTime.h, Anda harus menentukan _USE_MATH_DEFINESsebelum Anda memasukkan ATLComTime.h.

File ATLComTime.hmungkin disertakan secara tidak langsung dalam proyek Anda. Dalam kasus saya, satu kemungkinan urutan penyertaan adalah sebagai berikut:

proyek "stdafx.h"<afxdtctl.h><afxdisp.h><ATLComTime.h><math.h>

αλεχολυτ
sumber
Ini mungkin menjelaskan mengapa / Y- (nonaktifkan stdafx.h) akan menyelesaikan masalah, namun tetap menjelaskan mengapa menyediakan -D_USE_MATH_DEFINESdalam pengaturan kompiler default tidak cukup untuk menyelesaikan masalah ... Karena kompilasi melalui perintah Matlab mex untuk saya sendiri masalah, tidak begitu jelas untuk melacak ...
alias. bagus
1

Dengan CMake, itu akan terjadi

add_compile_definitions(_USE_MATH_DEFINES)

masuk CMakeLists.txt.

FLUXparticle
sumber
0

Seperti yang disarankan oleh user7860670, klik kanan pada proyek, pilih properti, arahkan ke C / C ++ -> Preprocessor dan tambahkan _USE_MATH_DEFINESke Definisi Preprocessor.

Itulah yang berhasil bagi saya.

Den-Jason
sumber