Yah, saya cukup terkejut bahwa alternatif untuk sintaks ini belum disebutkan. Mekanisme umum lainnya (tetapi lebih tua) adalah untuk memanggil fungsi yang tidak didefinisikan dan mengandalkan pengoptimal untuk mengkompilasi-keluar panggilan fungsi jika pernyataan Anda benar.
#define MY_COMPILETIME_ASSERT(test) \
do { \
extern void you_did_something_bad(void); \
if (!(test)) \
you_did_something_bad(void); \
} while (0)
Meskipun mekanisme ini berfungsi (selama optimisasi diaktifkan) ia memiliki kelemahan yaitu tidak melaporkan kesalahan hingga Anda menautkan, pada saat itu gagal menemukan definisi untuk fungsi you_did_something_bad (). Itu sebabnya pengembang kernel mulai menggunakan trik-trik seperti lebar bit-field berukuran negatif dan array berukuran negatif (yang kemudian berhenti memecah build di GCC 4.4).
Dalam simpati terhadap kebutuhan akan pernyataan waktu kompilasi, GCC 4.3 memperkenalkan error
atribut fungsi yang memungkinkan Anda untuk memperluas konsep yang lebih lama ini, tetapi menghasilkan kesalahan waktu kompilasi dengan pesan pilihan Anda - tidak ada lagi cryptic "array berukuran negatif "pesan kesalahan!
#define MAKE_SURE_THIS_IS_FIVE(number) \
do { \
extern void this_isnt_five(void) __attribute__((error( \
"I asked for five and you gave me " #number))); \
if ((number) != 5) \
this_isnt_five(); \
} while (0)
Bahkan, pada Linux 3.9, kami sekarang memiliki makro yang disebut compiletime_assert
yang menggunakan fitur ini dan sebagian besar makro bug.h
telah diperbarui. Namun, makro ini tidak dapat digunakan sebagai penginisialisasi. Namun, menggunakan ekspresi pernyataan (ekstensi-GCC lain), Anda bisa!
#define ANY_NUMBER_BUT_FIVE(number) \
({ \
typeof(number) n = (number); \
extern void this_number_is_five(void) __attribute__(( \
error("I told you not to give me a five!"))); \
if (n == 5) \
this_number_is_five(); \
n; \
})
Makro ini akan mengevaluasi parameternya tepat sekali (kalau-kalau ada efek samping) dan membuat kesalahan waktu kompilasi yang mengatakan, "Saya bilang jangan memberi saya lima!" jika ekspresi bernilai lima atau bukan konstanta waktu kompilasi.
Jadi mengapa kita tidak menggunakan ini alih-alih bidang bit berukuran negatif? Sayangnya, saat ini ada banyak pembatasan penggunaan ekspresi pernyataan, termasuk penggunaannya sebagai inisialisasi konstan (untuk konstanta enum, lebar bidang bit, dll.) Bahkan jika ekspresi pernyataan benar-benar konstan sendiri (yaitu, dapat sepenuhnya dievaluasi pada waktu kompilasi dan dinyatakan lulus __builtin_constant_p()
tes). Lebih lanjut, mereka tidak dapat digunakan di luar fungsi tubuh.
Semoga, GCC akan segera mengubah kekurangan ini dan memungkinkan ekspresi pernyataan konstan untuk digunakan sebagai inisialisasi konstan. Tantangannya di sini adalah spesifikasi bahasa yang mendefinisikan apa yang merupakan ekspresi konstanta hukum. C ++ 11 menambahkan kata kunci constexpr untuk tipe atau hal ini saja, tetapi tidak ada padanan dalam C11. Sementara C11 memang mendapatkan pernyataan statis, yang akan menyelesaikan bagian dari masalah ini, C11 tidak akan menyelesaikan semua kekurangan ini. Jadi saya berharap bahwa gcc dapat membuat fungsionalitas constexpr tersedia sebagai ekstensi melalui -std = gnuc99 & -std = gnuc11 atau semacamnya dan memungkinkan penggunaannya pada pernyataan pernyataan et. Al.