ฉันค่อนข้างประหลาดใจที่ไม่มีการกล่าวถึงทางเลือกในไวยากรณ์นี้ กลไกทั่วไปอื่น (แต่เก่ากว่า) คือการเรียกใช้ฟังก์ชันที่ไม่ได้กำหนดไว้และใช้เครื่องมือเพิ่มประสิทธิภาพเพื่อรวบรวมการเรียกใช้ฟังก์ชันหากการยืนยันของคุณถูกต้อง
#define MY_COMPILETIME_ASSERT(test) \
do { \
extern void you_did_something_bad(void); \
if (!(test)) \
you_did_something_bad(void); \
} while (0)
ในขณะที่กลไกนี้ทำงาน (ตราบเท่าที่เปิดใช้งานการปรับให้เหมาะสมที่สุด) ก็มีข้อเสียของการไม่รายงานข้อผิดพลาดจนกว่าคุณจะลิงก์ซึ่งในเวลานั้นมันล้มเหลวในการค้นหาคำจำกัดความสำหรับฟังก์ชั่น you_did_something_bad () นั่นเป็นสาเหตุที่นักพัฒนาเคอร์เนลเริ่มใช้ลูกเล่นเช่นความกว้างบิตฟิลด์ขนาดลบและอาร์เรย์ขนาดลบ (ภายหลังซึ่งหยุดการสร้างบิลด์ใน GCC 4.4)
ในความเห็นอกเห็นใจต่อความต้องการการยืนยันเวลารวบรวม GCC 4.3 ได้เปิดตัวerror
ฟังก์ชั่นฟังก์ชั่นที่ช่วยให้คุณสามารถขยายความคิดเก่า ๆ นี้ได้ แต่สร้างข้อผิดพลาดในการคอมไพล์เวลาด้วยข้อความที่คุณเลือก "ข้อความผิดพลาด!
#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)
ในความเป็นจริงในฐานะของ Linux 3.9 ตอนนี้เรามีมาโครที่เรียกcompiletime_assert
ใช้ซึ่งใช้คุณสมบัตินี้และมาโครส่วนใหญ่bug.h
ได้รับการอัพเดตตามนั้น อย่างไรก็ตามแมโครนี้ไม่สามารถใช้เป็นเครื่องมือเริ่มต้นได้ อย่างไรก็ตามการใช้คำสั่งแสดงออก (ส่วนขยาย GCC อื่น) คุณสามารถทำได้!
#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; \
})
มาโครนี้จะประเมินพารามิเตอร์ของมันหนึ่งครั้ง (ในกรณีที่มีผลข้างเคียง) และสร้างข้อผิดพลาดในการคอมไพล์เวลาที่ระบุว่า "ฉันบอกคุณว่าอย่าให้ฉันห้าอัน!" ถ้านิพจน์ประเมินถึงห้าหรือไม่ใช่ค่าคงที่เวลาคอมไพล์
เหตุใดเราจึงไม่ใช้สิ่งนี้แทนที่จะเป็นบิตบิตขนาดลบ อนิจจาในปัจจุบันมีข้อ จำกัด มากมายในการใช้คำสั่งนิพจน์รวมถึงการใช้เป็น initializers คงที่ (สำหรับค่าคงที่ enum ความกว้างบิตฟิลด์และอื่น ๆ ) แม้ว่านิพจน์คำสั่งจะคงที่อย่างสมบูรณ์ด้วยตนเอง (เช่นสามารถประเมินได้อย่างเต็มที่ ที่รวบรวมเวลาและอื่น ๆ ผ่าน__builtin_constant_p()
ทดสอบ) นอกจากนี้พวกเขาไม่สามารถใช้นอกร่างกายฟังก์ชั่น
หวังว่า GCC จะแก้ไขข้อบกพร่องเหล่านี้ในไม่ช้าและอนุญาตให้มีการใช้คำสั่งคงที่เป็นนิพจน์เริ่มต้นอย่างต่อเนื่อง ความท้าทายที่นี่คือข้อกำหนดภาษาที่กำหนดว่านิพจน์คงที่ทางกฎหมายคืออะไร C ++ 11 เพิ่มคำหลัก constexpr สำหรับประเภทหรือสิ่งนี้ แต่ไม่มีคู่ใน C11 ในขณะที่ C11 ได้รับการยืนยันแบบคงที่ซึ่งจะแก้ปัญหาบางส่วนของปัญหานี้จะไม่แก้ข้อบกพร่องเหล่านี้ทั้งหมด ดังนั้นฉันหวังว่า gcc สามารถทำให้การทำงานของ constexpr พร้อมใช้งานเป็นส่วนขยายผ่าน -std = gnuc99 & -std = gnuc11 หรือบางอย่างและอนุญาตให้ใช้กับนิพจน์คำสั่งและ อัล