_DEBUG vs NDEBUG


142

Definisi preprocessor mana yang harus digunakan untuk menentukan bagian debug kode?

Gunakan #ifdef _DEBUGatau #ifndef NDEBUGatau adakah cara yang lebih baik untuk melakukannya, misalnya #define MY_DEBUG?

Saya pikir _DEBUGVisual Studio spesifik, apakah standar NDEBUG?

Jawaban:


113

Visual Studio mendefinisikan _DEBUGketika Anda menentukan opsi /MTdatau /MDd, NDEBUGmenonaktifkan pernyataan standar-C. Gunakan jika perlu, yaitu _DEBUGjika Anda ingin kode debug Anda konsisten dengan teknik debugging MS CRT dan NDEBUGjika Anda ingin konsisten dengannya assert().

Jika Anda mendefinisikan makro debug Anda sendiri (dan Anda tidak meretas kompiler atau runtime C), hindari mulai nama dengan garis bawah, karena ini dicadangkan.


19
+1. NDEBUG secara khusus diizinkan untuk menjadi # undef'd dan # define'd dalam TU tunggal (dan memasukkan kembali <assert.h> mengubah pernyataan makro yang sesuai). Karena ini berbeda dari yang diharapkan / diinginkan, itu umum untuk menggunakan makro lain untuk mengontrol flag debug "compile-wide" seperti yang dikatakan jawaban ini.

1
Rupanya, itu adalah kompiler itu sendiri yang mendefinisikan makro ini dan bukan Visual Studio (IDE). Terima kasih banyak atas jawaban ini!
Niklas R

NDEBUG tidak didefinisikan saat menggunakan templat aplikasi dari Windows Driver Kit 8.1 juga. Dalam hal ini, Anda mungkin perlu mengandalkan _DEBUG.
navossoc

53

Apakah standar NDEBUG?

Ya itu adalah makro standar dengan semantic "Not Debug" untuk C89, C99, C ++ 98, C ++ 2003, C ++ 2011, C ++ 2014 standar. Tidak ada _DEBUGmakro dalam standar.

Standar C ++ 2003 mengirim pembaca di "halaman 326" di "17.4.2.1 Header" ke standar C.

NDEBUG itu serupa dengan Ini sama dengan pustaka C Standar.

Dalam C89 (programmer C menyebut standar ini sebagai standar C) di bagian "4.2 DIAGNOSTIK" dikatakan

http://port70.net/~nsz/c/c89/c89-draft.html

Jika NDEBUG didefinisikan sebagai nama makro pada titik di file sumber di mana disertakan, makro pernyataan didefinisikan hanya sebagai

     #define assert(ignore) ((void)0)

Jika melihat arti _DEBUGmakro di Visual Studio https://msdn.microsoft.com/en-us/library/b0084kay.aspx maka akan terlihat, bahwa makro ini secara otomatis ditentukan oleh сhoice versi perpustakaan runtime bahasa Anda.


50

Saya mengandalkan NDEBUG, karena itu adalah satu-satunya yang perilakunya distandardisasi di seluruh kompiler dan implementasi (lihat dokumentasi untuk makro pernyataan standar). Logika negatif adalah speedbump keterbacaan kecil, tapi itu adalah idiom umum yang dapat Anda adaptasi dengan cepat.

Untuk bergantung pada sesuatu seperti _DEBUGakan bergantung pada detail implementasi dari kompiler dan implementasi perpustakaan tertentu. Kompiler lain mungkin atau mungkin tidak memilih konvensi yang sama.

Opsi ketiga adalah mendefinisikan makro Anda sendiri untuk proyek Anda, yang cukup masuk akal. Memiliki makro Anda sendiri memberi Anda portabilitas di seluruh implementasi dan memungkinkan Anda untuk mengaktifkan atau menonaktifkan kode debug Anda secara independen dari pernyataan. Meskipun, secara umum, saya menyarankan agar tidak memiliki kelas informasi debug yang berbeda yang diaktifkan pada waktu kompilasi, karena hal itu menyebabkan peningkatan jumlah konfigurasi yang harus Anda bangun (dan uji) untuk manfaat yang bisa dibilang kecil.

Dengan salah satu opsi ini, jika Anda menggunakan kode pihak ketiga sebagai bagian dari proyek Anda, Anda harus mengetahui konvensi mana yang digunakannya.


1
#if !defined(NDEBUG)<- @HostileFork bukankah itu yang Anda maksud? #ifbukan #ifdef?
Bob Stein

1
Komentar asli dikoreksi melalui @BobStein: "Sesuatu yang telah saya lakukan untuk (sedikit) mengurangi keterbacaan" speedbump "adalah ketika berbicara tentang penggunaan kondisi tanpa-debug #ifdef NDEBUG... tapi kemudian minta perhatian khusus pada logika negatif dengan #if !defined(NDEBUG). Kalau tidak, agak sulit untuk menangkap #ifndef NDEBUG"
HostileFork mengatakan jangan percaya SE

17

Makro NDEBUGmengontrol apakah assert()pernyataan aktif atau tidak.

Dalam pandangan saya, itu terpisah dari debugging lain - jadi saya menggunakan sesuatu selain NDEBUGuntuk mengontrol informasi debug dalam program. Apa yang saya gunakan bervariasi, tergantung pada kerangka kerja saya; sistem yang berbeda memiliki makro yang memungkinkan yang berbeda, dan saya menggunakan apa pun yang sesuai.

Jika tidak ada kerangka kerja, saya akan menggunakan nama tanpa garis bawah utama; mereka cenderung dicadangkan untuk 'implementasi' dan saya mencoba untuk menghindari masalah dengan tabrakan nama - jadi ketika nama adalah makro.


Bisakah Anda menjelaskan mengapa Anda menganggap pernyataan berbeda dari jenis debug lain? Dalam skenario apa Anda ingin satu dan bukan yang lain?
Adrian McCarthy

4
Saya tetap membuat pernyataan tetap aktif walaupun saya tidak mengkompilasi fasilitas debugging atau tracing lain ke dalam kode. Penegasan mengidentifikasi situasi yang tidak mungkin. Pelacakan dan debugging umum adalah IMO yang sepenuhnya terpisah dari itu.
Jonathan Leffler

2
@AdrianMcCarthy: jika SEMUA debug Anda diaktifkan, ini dapat menyebabkan program berjalan dengan sangat lambat. Jadi, sangat umum untuk mengategorikan jenis debugging, dan memungkinkan orang untuk mengaktifkan / menonaktifkannya secara terpisah. MSVC memiliki dua atau tiga yang mereka gunakan untuk mengaktifkan / menonaktifkan berbagai debugging untuk perpustakaan standar, seperti std :: vector.
Mooing Duck

@ MoooDuck: Setuju, tetapi bedakan antara 'debugging tersedia dan diaktifkan' dan 'debugging tersedia tetapi dinonaktifkan' dan 'debugging tidak tersedia'. Keputusan yang tersedia / tidak tersedia adalah masalah waktu kompilasi (dalam kode C atau C ++), dan yang diaktifkan / dinonaktifkan kemudian merupakan keputusan runtime ketika debugging tersedia. Hanya sistem debugging paling kasar yang bekerja dengan mode 'tersedia berarti diaktifkan'. (Yang mengatakan, minyak mentah bisa efektif, dan ada banyak sekali minyak mentah - tetapi cukup efektif - sistem debug di luar sana di alam liar!)
Jonathan Leffler

2
@ MoooDuck: Ya, beberapa kode debug mungkin bervariasi lambat. Dalam hal ini, Anda mungkin ingin cara untuk mengontrol apakah kode lambat berjalan secara independen dari pemeriksaan sepele. Tapi itu tidak sama dengan menempatkan asersi dalam satu kategori dan #if-kontrol kode di yang lain. assert(huge_object.IsValid());mungkin lambat sementara assert(ptr != nullptr);mungkin tidak. Saya setuju dengan Jonathan bahwa logging dan tracing mungkin harus berbeda dari pernyataan, setidaknya dalam proyek yang lebih besar, tetapi saya tidak menganggap logging atau tracing sebagai kode debug, itulah sebabnya saya meminta klarifikasi.
Adrian McCarthy

6

Konsisten dan tidak masalah yang mana. Juga jika karena alasan tertentu Anda harus melakukan interop dengan program atau alat lain menggunakan pengenal DEBUG tertentu itu mudah dilakukan

#ifdef THEIRDEBUG
#define MYDEBUG
#endif //and vice-versa

4

Sayangnya DEBUGkelebihan beban. Misalnya, disarankan untuk selalu menghasilkan dan menyimpan file pdb untuk RELEASE build. Yang berarti salah satu opsi -Zxflag, dan -DEBUGlinker. Sementara _DEBUGberkaitan dengan versi debug khusus perpustakaan runtime seperti panggilan ke mallocdan free. Maka NDEBUGakan menonaktifkan asersi.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.