Apakah ini praktik yang baik untuk menggunakan #ifdef selama pengembangan untuk beralih di antara berbagai jenis perilaku? Sebagai contoh, saya ingin mengubah perilaku kode yang ada, saya punya beberapa ide bagaimana mengubah perilaku dan perlu beralih di antara implementasi yang berbeda untuk menguji dan membandingkan berbagai pendekatan yang berbeda. Biasanya perubahan dalam kode sangat kompleks dan berpengaruh pada metode yang berbeda dalam file yang berbeda.
Saya biasanya memperkenalkan beberapa pengidentifikasi dan melakukan sesuatu seperti itu
void foo()
{
doSomething1();
#ifdef APPROACH1
foo_approach1();
#endif
doSomething2();
#ifdef APPROACH2
foo_approach2();
#endif
}
void bar()
{
doSomething3();
#ifndef APPROACH3
doSomething4();
#endif
doSomething5();
#ifdef APPROACH2
bar_approach2();
#endif
}
int main()
{
foo();
bar();
return 0;
}
Ini memungkinkan untuk beralih di antara berbagai pendekatan dengan cepat dan melakukan semuanya hanya dalam satu salinan kode sumber. Apakah ini pendekatan yang baik untuk pembangunan atau apakah ada praktik yang lebih baik?
sumber
#ifdef
blok jika blok dimatikan. Kami mengalami kasus di mana kode dapat dengan mudah menjadi basi dan tidak dapat dikompilasi jika Anda tidak secara rutin membangun semua jalur.#ifdefs
kurang rumit.Jawaban:
Saya lebih suka menggunakan cabang kontrol versi untuk use case ini. Itu memungkinkan Anda untuk berbeda di antara implementasi, mempertahankan sejarah yang terpisah untuk masing-masing, dan ketika Anda telah membuat keputusan dan perlu menghapus salah satu versi, Anda hanya membuang cabang itu alih-alih melalui pengeditan rawan kesalahan.
sumber
git
sangat mahir dalam hal semacam ini. Mungkin tidak begitu banyak dengansvn
,hg
atau yang lain, tetapi masih bisa dilakukan.git branch
!Saat Anda memegang palu, semuanya terlihat seperti paku. Sangat menggoda setelah Anda tahu cara
#ifdef
menggunakannya sebagai semacam cara untuk mendapatkan perilaku khusus dalam program Anda. Saya tahu karena saya melakukan kesalahan yang sama.Saya mewarisi program lama yang ditulis dalam MFC C ++ yang sudah digunakan
#ifdef
untuk mendefinisikan nilai platform-spesifik. Ini berarti saya dapat mengkompilasi program saya untuk digunakan pada platform 32-bit atau platform 64-bit hanya dengan mendefinisikan (atau dalam beberapa kasus tidak mendefinisikan) nilai makro tertentu.Masalahnya kemudian muncul bahwa saya perlu menulis perilaku khusus untuk klien. Saya bisa membuat cabang dan membuat basis kode terpisah untuk klien, tetapi itu akan membuat neraka pemeliharaan. Saya bisa juga menetapkan nilai konfigurasi untuk dibaca oleh program saat startup dan menggunakan nilai-nilai ini untuk menentukan perilaku, tetapi saya kemudian harus membuat pengaturan khusus untuk menambahkan nilai konfigurasi yang tepat ke file konfigurasi untuk setiap klien.
Saya tergoda, dan saya menyerah. Saya menulis
#ifdef
bagian-bagian dalam kode saya untuk membedakan berbagai perilaku. Jangan salah, awalnya tidak ada yang berlebihan. Perubahan perilaku yang sangat kecil dibuat yang memungkinkan saya untuk mendistribusikan kembali versi program kepada klien kami dan saya tidak perlu memiliki lebih dari satu versi basis kode.Seiring waktu ini menjadi perawatan neraka pula karena program tidak lagi berperilaku secara konsisten di seluruh papan. Jika saya ingin menguji versi program, saya harus tahu siapa kliennya. Kode, meskipun saya mencoba menguranginya menjadi satu atau dua file header, sangat berantakan dan pendekatan perbaikan cepat yang
#ifdef
disediakan berarti solusi tersebut menyebar ke seluruh program seperti kanker ganas.Sejak saya telah belajar pelajaran saya, dan Anda juga harus. Gunakan jika Anda benar-benar harus, dan gunakan secara ketat untuk perubahan platform. Cara terbaik untuk mendekati perbedaan perilaku antara program (dan karena itu klien) adalah mengubah hanya konfigurasi yang dimuat saat startup. Program ini tetap konsisten dan keduanya menjadi lebih mudah dibaca serta untuk debug.
sumber
Untuk sementara tidak ada yang salah dengan apa yang Anda lakukan (katakan, sebelum check-in): ini adalah cara yang bagus untuk menguji berbagai kombinasi teknik, atau mengabaikan bagian kode (meskipun itu berbicara tentang masalah di dalam dan dari dirinya sendiri).
Tapi satu kata peringatan: jangan biarkan cabang #ifdef ada sedikit lebih membuat frustrasi daripada membuang-buang waktu saya membaca hal yang sama menerapkan empat cara yang berbeda, hanya untuk mencari tahu mana yang harus saya baca .
Membaca sebuah #ifdef membutuhkan usaha karena Anda harus benar-benar ingat untuk melewatinya! Jangan membuatnya lebih sulit dari yang seharusnya.
Gunakan #ifdefs semudah mungkin. Pada umumnya ada cara-cara yang dapat Anda lakukan ini dalam lingkungan pengembangan Anda untuk perbedaan permanen , seperti Debug / Rilis membangun, atau untuk arsitektur yang berbeda.
Saya telah menulis fitur pustaka yang bergantung pada versi pustaka yang disertakan, yang membutuhkan #ifdef splits. Jadi kadang-kadang itu mungkin satu-satunya cara, atau yang termudah, tetapi meskipun begitu Anda harus kesal tentang menjaga mereka.
sumber
Menggunakan # ifdefs seperti itu membuat kode sangat sulit dibaca.
Jadi, tidak, jangan gunakan #ifdefs seperti itu.
Mungkin ada banyak argumen mengapa tidak menggunakan ifdefs, bagi saya ini sudah cukup.
Dapat melakukan banyak hal yang dapat dilakukannya:
Semua tergantung pada pendekatan apa yang didefinisikan atau tidak. Apa yang dilakukannya sama sekali tidak jelas pada tampilan pertama.
sumber