Beberapa penjelasan. Yang pertama bersifat umum, yang kedua khusus untuk makro praprosesor C dengan parameter:
Alur kontrol
Saya telah melihat ini digunakan dalam kode C biasa. Pada dasarnya, ini adalah versi goto yang lebih aman, karena Anda dapat keluar darinya dan semua memori dibersihkan dengan benar.
Mengapa sesuatu- goto
seperti itu bagus? Nah, jika Anda memiliki kode di mana hampir setiap baris dapat mengembalikan kesalahan, tetapi Anda perlu bereaksi terhadap semuanya dengan cara yang sama (misalnya dengan menyerahkan kesalahan kepada pemanggil Anda setelah membersihkan), biasanya lebih mudah dibaca untuk menghindari if( error ) { /* cleanup and error string generation and return here */ }
as itu menghindari duplikasi kode pembersihan.
Namun, di C ++ Anda memiliki pengecualian + RAII untuk tujuan ini, jadi saya akan menganggapnya gaya pengkodean yang buruk.
Pemeriksaan titik koma
Jika Anda lupa titik koma setelah pemanggilan makro mirip fungsi, argumen mungkin berkontraksi dengan cara yang tidak diinginkan dan dikompilasi menjadi sintaks yang valid. Bayangkan makro
#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");
Itu secara tidak sengaja disebut sebagai
if( foo )
PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
doSomethingElse();
"Lain" akan dianggap terkait dengan gDebugModeOn
, jadi bila foo
ada false
, kebalikan dari apa yang dimaksudkan akan terjadi.
Menyediakan ruang lingkup untuk variabel sementara.
Karena do / while memiliki tanda kurung kurawal, variabel sementara memiliki ruang lingkup yang jelas dan tidak dapat mereka hindari.
Menghindari peringatan "titik koma yang mungkin tidak diinginkan"
Beberapa makro hanya diaktifkan di build debug. Anda mendefinisikannya seperti:
#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n)
#endif
Sekarang jika Anda menggunakan ini dalam rilis, build di dalam kondisional, itu akan dikompilasi ke
if( foo )
;
Banyak kompiler melihat ini sama dengan
if( foo );
Yang sering ditulis secara tidak sengaja. Jadi Anda mendapat peringatan. Do {} while (false) menyembunyikan ini dari kompiler, dan diterima olehnya sebagai indikasi bahwa Anda benar-benar - ingin melakukan apa-apa di sini.
Menghindari pengambilan garis dengan persyaratan
Makro dari contoh sebelumnya:
if( foo )
DBG_PRINT_NUM(42)
doSomething();
Sekarang, dalam build debug, karena kita juga biasa memasukkan titik koma, kompilasi ini baik-baik saja. Namun, dalam rilis build ini tiba-tiba berubah menjadi:
if( foo )
doSomething();
Atau lebih jelas diformat
if( foo )
doSomething();
Yang sama sekali bukan yang dimaksudkan. Menambahkan do {...} while (false) di sekitar makro mengubah titik koma yang hilang menjadi kesalahan kompilasi.
Apa artinya bagi OP?
Secara umum, Anda ingin menggunakan pengecualian di C ++ untuk penanganan kesalahan, dan template, bukan makro. Namun, dalam kasus yang sangat jarang terjadi di mana Anda masih memerlukan makro (misalnya saat membuat nama kelas menggunakan penempelan token) atau dibatasi ke C biasa, ini adalah pola yang berguna.