Ini mungkin masalah gaya, tetapi ada sedikit perbedaan dalam tim pengembang kami dan saya bertanya-tanya apakah ada orang lain yang punya ide tentang masalah ini ...
Pada dasarnya, kami memiliki beberapa pernyataan cetak debug yang kami matikan selama pengembangan normal. Secara pribadi saya lebih suka melakukan hal berikut:
//---- SomeSourceFile.cpp ----
#define DEBUG_ENABLED (0)
...
SomeFunction()
{
int someVariable = 5;
#if(DEBUG_ENABLED)
printf("Debugging: someVariable == %d", someVariable);
#endif
}
Beberapa tim lebih menyukai yang berikut ini:
// #define DEBUG_ENABLED
...
SomeFunction()
{
int someVariable = 5;
#ifdef DEBUG_ENABLED
printf("Debugging: someVariable == %d", someVariable);
#endif
}
... metode mana yang terdengar lebih baik untuk Anda dan mengapa? Perasaan saya adalah yang pertama lebih aman karena selalu ada sesuatu yang didefinisikan dan tidak ada bahaya bisa menghancurkan definisi lain di tempat lain.
c++
c
if-statement
coding-style
c-preprocessor
Jon Cage
sumber
sumber
#if
, Anda juga dapat menggunakan#elif
secara konsisten, tidak seperti dengan#ifdef
. Jadi, alih-alih hanya menggunakan#define BLAH
, gunakan#define BLAH 1
dengan#if BLAH
, dll ...Jawaban:
Reaksi awal saya
#ifdef
, tentu saja , tetapi saya pikir#if
sebenarnya memiliki beberapa keuntungan signifikan untuk ini - inilah alasannya:Pertama, Anda dapat menggunakan
DEBUG_ENABLED
preprocessor dan tes terkompilasi. Contoh - Seringkali, saya ingin waktu tunggu yang lebih lama saat debug diaktifkan, jadi dengan menggunakan#if
, saya bisa menulis ini... dari pada ...
Kedua, Anda berada dalam posisi yang lebih baik jika Anda ingin bermigrasi dari
#define
konstanta global ke konstanta global.#define
s biasanya disukai oleh sebagian besar programmer C ++.Dan, Ketiga, Anda mengatakan Anda memiliki perbedaan dalam tim Anda. Dugaan saya adalah ini berarti anggota yang berbeda telah mengadopsi pendekatan yang berbeda, dan Anda perlu membuat standar. Aturan yang
#if
merupakan pilihan yang lebih disukai berarti bahwa kode yang digunakan#ifdef
akan mengkompilasi -dan dijalankan- bahkan ketikaDEBUG_ENABLED
salah. Dan jauh lebih mudah untuk melacak dan menghapus keluaran debug yang dihasilkan saat tidak semestinya daripada sebaliknya.Oh, dan poin keterbacaan kecil. Anda harus dapat menggunakan true / false daripada 0/1 di Anda
#define
, dan karena nilainya adalah token leksikal tunggal, ini adalah satu-satunya saat Anda tidak memerlukan tanda kurung di sekitarnya.dari pada
sumber
#ifdef
adalah bahwa ia bekerja dengan hal-hal yang tidak ditentukan; apakah mereka tidak didefinisikan dengan sengaja atau karena salah ketik atau apa pun yang Anda alami.#if DEBUG_ENBALED
bukan kesalahan yang terdeteksi oleh preprocessor. JikaDEBUG_ENBALED
tidak ditentukan, itu diperluas ke token0
dalam#if
arahan.Keduanya mengerikan. Sebaliknya, lakukan ini:
Kemudian kapan pun Anda membutuhkan kode debug, masukkan ke dalamnya
D();
. Dan program Anda tidak tercemar dengan labirin yang mengerikan#ifdef
.sumber
#ifdef
hanya memeriksa apakah token ditentukan, diberikankemudian
sumber
Kami mengalami masalah yang sama di beberapa file dan selalu ada masalah dengan orang-orang yang lupa menyertakan file "tanda fitur" (Dengan basis kode> 41.000 file, hal ini mudah dilakukan).
Jika Anda memiliki fitur.h:
Tapi kemudian Anda lupa menyertakan file header di file.cpp:
Kemudian Anda mendapat masalah, kompilator menafsirkan COOL_FEATURE tidak didefinisikan sebagai "salah" dalam kasus ini dan gagal untuk memasukkan kode. Ya, gcc mendukung penandaan yang menyebabkan kesalahan untuk makro yang tidak ditentukan ... tetapi sebagian besar kode pihak ke-3 menentukan atau tidak menentukan fitur, jadi ini tidak akan portabel.
Kami telah mengadopsi cara portabel untuk mengoreksi kasus ini serta menguji status fitur: makro fungsi.
jika Anda mengubah fitur di atas. h menjadi:
Tapi kemudian Anda lagi lupa menyertakan file header di file.cpp:
Praprosesor akan mengalami error karena penggunaan makro fungsi yang tidak ditentukan.
sumber
Untuk keperluan melakukan kompilasi bersyarat, #if dan #ifdef hampir sama, tetapi tidak sepenuhnya. Jika kompilasi bersyarat Anda bergantung pada dua simbol, maka #ifdef tidak akan berfungsi dengan baik. Misalnya, Anda memiliki dua simbol kompilasi bersyarat, PRO_VERSION dan TRIAL_VERSION, Anda mungkin memiliki sesuatu seperti ini:
Menggunakan #ifdef di atas menjadi jauh lebih rumit, terutama membuat bagian #else berfungsi.
Saya mengerjakan kode yang menggunakan kompilasi kondisional secara ekstensif dan kami memiliki campuran #if & #ifdef. Kita cenderung menggunakan # ifdef / # ifndef untuk kasus sederhana dan #if setiap kali dua atau lebih simbol sedang dievaluasi.
sumber
#if defined
apadefined
itu kata kunci atau?Saya pikir ini sepenuhnya soal gaya. Tidak ada yang benar-benar memiliki keunggulan dibandingkan yang lain.
Konsistensi lebih penting daripada pilihan tertentu, jadi saya sarankan Anda berkumpul dengan tim Anda dan memilih satu gaya, dan menaatinya.
sumber
Saya sendiri lebih suka:
Karena lebih mudah untuk membuat kode yang mencari kondisi sebaliknya lebih mudah dikenali:
vs.
sumber
#if ! defined
agar!
lebih menonjol dan sulit untuk dilewatkan.Ini masalah gaya. Tetapi saya merekomendasikan cara yang lebih ringkas untuk melakukan ini:
Anda melakukan ini sekali, lalu selalu gunakan debug_print () untuk mencetak atau tidak melakukan apa pun. (Ya, ini akan terkompilasi dalam kedua kasus.) Dengan cara ini, kode Anda tidak akan dirusak dengan arahan preprocessor.
Jika Anda mendapatkan peringatan "ekspresi tidak berpengaruh" dan ingin menyingkirkannya, berikut adalah alternatifnya:
sumber
#if
memberi Anda opsi untuk menyetelnya ke 0 untuk mematikan fungsionalitas, sambil tetap mendeteksi bahwa sakelar itu ada.Secara pribadi saya selalu
#define DEBUG 1
jadi saya bisa menangkapnya dengan #if atau #ifdefsumber
#define DEBUG 1
. Tidak#define DEBUG=1
#if dan #define MY_MACRO (0)
Menggunakan #if berarti Anda membuat makro "definisikan", yaitu sesuatu yang akan dicari di kode untuk diganti dengan "(0)". Ini adalah "neraka makro" yang saya benci untuk dilihat di C ++, karena mencemari kode dengan kemungkinan modifikasi kode.
Sebagai contoh:
memberikan kesalahan berikut pada g ++:
Hanya satu kesalahan.
Artinya makro Anda berhasil berinteraksi dengan kode C ++ Anda: Panggilan ke fungsi berhasil. Dalam kasus sederhana ini, itu lucu. Tetapi pengalaman saya sendiri dengan makro yang bermain diam-diam dengan kode saya tidak penuh dengan kegembiraan dan kepenuhan, jadi ...
#ifdef dan #define MY_MACRO
Menggunakan #ifdef berarti Anda "mendefinisikan" sesuatu. Bukan berarti Anda memberinya nilai. Itu masih mencemari, tapi setidaknya, itu akan "digantikan oleh tidak ada", dan tidak dilihat oleh kode C ++ sebagai pernyataan kode yang tertinggal. Kode yang sama di atas, dengan definisi sederhana, itu:
Memberikan peringatan berikut:
Begitu...
Kesimpulan
Saya lebih suka hidup tanpa makro dalam kode saya, tetapi karena beberapa alasan (mendefinisikan pelindung header, atau makro debug), saya tidak bisa.
Tapi setidaknya, saya ingin membuatnya menjadi paling tidak interaktif dengan kode C ++ saya yang sah. Yang berarti menggunakan #define tanpa nilai, menggunakan #ifdef dan #ifndef (atau bahkan #if didefinisikan seperti yang disarankan oleh Jim Buck), dan yang terpenting, memberi mereka nama yang begitu lama dan begitu asing sehingga tidak ada orang waras yang akan menggunakannya itu "secara kebetulan", dan tidak akan mempengaruhi kode C ++ yang sah.
Posting Scriptum
Sekarang, saat saya membaca kembali posting saya, saya bertanya-tanya apakah saya seharusnya tidak mencoba menemukan beberapa nilai yang tidak akan pernah menjadi C ++ yang benar untuk ditambahkan ke definisi saya. Sesuatu seperti
yang dapat digunakan dengan #ifdef dan #ifndef, tetapi tidak membiarkan kode dikompilasi jika digunakan di dalam suatu fungsi ... Saya mencoba ini dengan sukses di g ++, dan itu memberikan kesalahan:
Menarik. :-)
sumber
Itu sama sekali bukan masalah gaya. Juga pertanyaannya sayangnya salah. Anda tidak dapat membandingkan arahan preprocessor ini dalam arti lebih baik atau lebih aman.
berarti "jika makro ditentukan" atau "jika makro ada". Nilai makro tidak menjadi masalah di sini. Bisa apa saja.
jika selalu dibandingkan dengan suatu nilai. Dalam contoh di atas, ini adalah perbandingan implisit standar:
contoh untuk penggunaan #if
Anda sekarang dapat meletakkan definisi CFLAG_EDITION baik di kode Anda
atau Anda dapat mengatur makro sebagai bendera kompilator. Lihat juga di sini .
sumber
Yang pertama tampak lebih jelas bagi saya. Tampaknya lebih alami menjadikannya sebagai bendera dibandingkan dengan didefinisikan / tidak ditentukan.
sumber
Keduanya sama persis. Dalam penggunaan idiomatik, #ifdef digunakan hanya untuk memeriksa definisi (dan apa yang saya gunakan dalam contoh Anda), sedangkan #if digunakan dalam ekspresi yang lebih kompleks, seperti #if ditentukan (A) &&! Didefinisikan (B).
sumber
Sedikit OT, tetapi menyalakan / mematikan logging dengan preprocessor jelas kurang optimal di C ++. Ada alat logging yang bagus seperti Apache's log4cxx yang merupakan open-source dan tidak membatasi cara Anda mendistribusikan aplikasi. Mereka juga memungkinkan Anda untuk mengubah level logging tanpa kompilasi ulang, memiliki overhead yang sangat rendah jika Anda mematikan logging, dan memberi Anda kesempatan untuk sepenuhnya mematikan logging dalam produksi.
sumber
Saya biasa menggunakan
#ifdef
, tetapi ketika saya beralih ke Doxygen untuk dokumentasi, saya menemukan bahwa makro yang dikomentari tidak dapat didokumentasikan (atau, setidaknya, Doxygen menghasilkan peringatan). Ini berarti saya tidak dapat mendokumentasikan makro pengalih fitur yang saat ini tidak diaktifkan.Meskipun dimungkinkan untuk menentukan makro hanya untuk Doxygen, ini berarti bahwa makro di bagian kode yang tidak aktif akan didokumentasikan juga. Saya pribadi ingin menunjukkan sakelar fitur dan sebaliknya hanya mendokumentasikan apa yang saat ini dipilih. Lebih jauh lagi, membuat kodenya cukup berantakan jika ada banyak macro yang harus didefinisikan hanya saat Doxygen memproses file tersebut.
Oleh karena itu, dalam kasus ini, lebih baik untuk selalu mendefinisikan makro dan penggunaan
#if
.sumber
Saya selalu menggunakan tanda #ifdef dan compiler untuk mendefinisikannya ...
sumber
Alternatifnya, Anda bisa mendeklarasikan konstanta global, dan menggunakan C ++ if, sebagai ganti preprocessor #if. Kompilator harus mengoptimalkan cabang yang tidak terpakai untuk Anda, dan kode Anda akan lebih bersih.
Inilah yang dikatakan C ++ Gotchas oleh Stephen C. Dewhurst tentang penggunaan # if.
sumber
Ada perbedaan dalam hal cara berbeda untuk menentukan definisi bersyarat untuk driver:
keluaran:
Artinya, itu
-DA
adalah sinonim untuk-DA=1
dan jika nilai dihilangkan, maka hal itu dapat menyebabkan masalah jika#if A
digunakan.sumber
Saya suka
#define DEBUG_ENABLED (0)
ketika Anda mungkin menginginkan beberapa level debug. Sebagai contoh:Mempermudah untuk men-debug kebocoran memori, tanpa semua baris log itu menghalangi Anda untuk men-debug hal-hal lain.
Juga di
#ifndef
sekitar define membuatnya lebih mudah untuk memilih level debug tertentu pada commandline:Jika bukan karena ini, saya akan memberikan keuntungan
#ifdef
karena bendera compiler / make akan diganti oleh yang ada di file. Jadi Anda tidak perlu khawatir tentang mengubah kembali header sebelum melakukan komit.sumber