Bu sözdizimine alternatiflerden bahsetmediğim için oldukça şaşırdım. Başka bir yaygın (ancak daha eski) mekanizma, iddianız doğruysa işlev çağrısını derlemek için tanımlanmamış bir işlevi çağırmak ve optimize ediciye güvenmektir.
#define MY_COMPILETIME_ASSERT(test) \
do { \
extern void you_did_something_bad(void); \
if (!(test)) \
you_did_something_bad(void); \
} while (0)
Bu mekanizma çalışırken (optimizasyonlar etkin olduğu sürece) bağlantı yapana kadar bir hata raporlamamanın dezavantajı vardır, bu sırada you_did_something_bad () işlevinin tanımını bulamaz. Bu nedenle çekirdek geliştiricileri, negatif boyutlu bit alanı genişlikleri ve negatif boyutlu diziler (daha sonra GCC 4.4'te yapıları kırmayı durduran) gibi hileler kullanmaya başlayanlar.
Derleme zamanı iddialarına duyulan sempati duyulduğunda, GCC 4.3 , bu eski konsepte uzanmanıza izin veren error
fonksiyon özelliğini tanıttı , ancak seçtiğiniz bir mesajla derleme zamanı hatası oluşturdu - artık şifreli olmayan "negatif boyutlu dizi " hata mesajları!
#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)
Aslında, Linux 3.9'dan itibaren, şimdi compiletime_assert
bu özelliği kullanan bir makro var ve makroların çoğu bug.h
buna göre güncellendi. Yine de, bu makro bir başlatıcı olarak kullanılamaz. Ancak, deyim ifadeleriyle (başka bir GCC C uzantısı) kullanarak yapabilirsiniz!
#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; \
})
Bu makro parametresini tam olarak bir kez değerlendirir (yan etkileri olması durumunda) ve "Bana beş tane vermemeni söylemiştim!" ifade beş olarak değerlendirilirse veya derleme zamanı sabiti değilse.
Peki bunu neden negatif boyutlu bit alanları yerine kullanmıyoruz? Ne yazık ki, ifade ifadesi tamamen kendiliğinden sabit olsa bile (yani, tam olarak değerlendirilebilir), sabit başlatıcılar (numara sabitleri, bit-alan genişliği, vb. İçin) olarak kullanımları da dahil olmak üzere, ifade ifadelerinin kullanımında birçok kısıtlama vardır. derleme zamanında ve aksi takdirde __builtin_constant_p()
testi geçer ). Ayrıca, bir işlev gövdesi dışında kullanılamazlar.
Umarım, GCC bu eksiklikleri yakında değiştirecek ve sabit deyim ifadelerinin sabit başlatıcılar olarak kullanılmasına izin verecektir. Buradaki zorluk, yasal sabit bir ifadenin ne olduğunu tanımlayan dil belirtimidir. C ++ 11, yalnızca bu tür veya şey için constexpr anahtar sözcüğünü ekledi, ancak C11'de herhangi bir karşılık bulunmuyor. C11, bu sorunun bir kısmını çözecek statik iddialar alırken, tüm bu eksiklikleri çözmeyecektir. Bu yüzden umuyorum ki gcc bir constexpr işlevselliğini -std = gnuc99 & -std = gnuc11 ya da bu gibi bir uzantı olarak kullanılabilir hale getirebilir ve deyim ifadeleri et. ark.