Exercises — Compile-time assertions — static_assert
5.1.31 · D4· Coding › C Programming › Compile-time assertions — static_assert
Shuru karne se pehle, ek shared vocabulary reminder taaki koi symbol bina explanation ke use na ho:
Level 1 — Recognition
Exercise 1.1
Har snippet ke liye yes/no answer do: kya condition ek constant expression hai jo static_assert accept karega?
static_assert(sizeof(long) >= 4, "a"); // (A)
int k = 8; static_assert(k == 8, "b"); // (B)
static_assert(3 + 4 == 7, "c"); // (C)
static_assert(getchar() != 0, "d"); // (D)Recall Solution
- (A) YES.
sizeof(long)compiler ke dwara fix hota hai → constant. - (B) NO.
kek runtime variable hai; bhale hi is line par uski value8ho, language sirf compile-time constants allow karti hai.kke liye plainassertuse karo. - (C) YES. Sab literals hain; compiler
7 == 7→1compute karta hai. - (D) NO.
getchar()ek function call hai — yeh value tabhi produce kar sakta hai jab program chal raha ho.
Exercise 1.2
C11 mein static_assert ki friendly spelling likhne ke liye kaun sa header #include karna zaroori hai? Aur agar kuch include na karo toh raw keyword kya hai?
Recall Solution
- Header:
<assert.h>(dekho Header <assert.h>). - Raw C11 keyword:
_Static_assert. C23 meinstatic_assertkhud ek keyword hai aur kisi header ki zaroorat nahi (dekho C11 vs C23 language features).
Level 2 — Application
Exercise 2.1
Ek algorithm 8 flags ko ek byte mein pack karta hai. Ek static_assert likho (C11-style, message ke saath) jo guarantee kare ki char exactly 8 bits ka hai, uski byte count check karke. (CHAR_BIT use karo <limits.h> se.)
Recall Solution
#include <assert.h>
#include <limits.h>
static_assert(CHAR_BIT == 8, "This packing assumes 8-bit bytes");CHAR_BIT ek #defined constant hai → poori condition constant hai. Kisi bhi (rare) machine par jahan CHAR_BIT != 8 ho, build ruk jaata hai bit-packing bug ship hone se pehle.
Exercise 2.2
Aapke paas ek lookup table hai aur ek matching count. static_assert fill karo taaki dono sync mein rahe:
enum { STATE_COUNT = 4 };
const char *state_name[] = { "idle", "run", "pause", "stop" };
static_assert( /* ??? */ , "state_name[] out of sync with STATE_COUNT");Recall Solution
static_assert(sizeof(state_name)/sizeof(state_name[0]) == STATE_COUNT,
"state_name[] out of sync with STATE_COUNT");sizeof(state_name) = array ke total bytes; sizeof(state_name[0]) = ek element (ek pointer) ke bytes. Unka ratio hai elements ki sankhya, jo compile time par pata hoti hai. Abhi yeh 4 == STATE_COUNT → pass karta hai. Ek 5th name add karo bina enum bump kiye aur yeh 5 == 4 → build fail ho jaata hai. Dekho sizeof operator aur Enumerations (enum).
Exercise 2.3
Ek static_assert likho ki #defined ALIGNMENT of 16 ek positive power of two hai.
Recall Solution
#define ALIGNMENT 16
static_assert(ALIGNMENT > 0 && (ALIGNMENT & (ALIGNMENT - 1)) == 0,
"ALIGNMENT must be a positive power of two");Trick x & (x-1) x ka lowest set bit clear karta hai; power of two ke liye exactly ek set bit hota hai, isliye result 0 hota hai. 16 (10000₂) ke liye, 16 & 15 = 10000₂ & 01111₂ = 0 → pass. Extra ALIGNMENT > 0 degenerate case 0 se bachata hai, jisme 0 & -1 == 0 galat taur par pass ho jaata.
Level 3 — Analysis
Exercise 3.1
Yeh code aapke laptop par compile hota hai lekin ek teammate build error report karta hai. Exactly batao kaunsi line fail ho rahi hai aur kyun, aur isse portable kaise banayein.
#include <assert.h>
static_assert(sizeof(void*) == 8, "need 64-bit pointers");Recall Solution
Koi syntactically galat nahi hai. Failure semantic hai: 32-bit target par sizeof(void*) 4 hota hai, isliye 4 == 8 → 0 → build "need 64-bit pointers" ke saath ruk jaata hai. Yahi static_assert ka kaam hai — usne ek galat assumption teammate ki machine par build time par pakad li. Isse portable banane ke liye, ya toh dono widths ko #if/alag code paths se handle karo, ya assertion ko relax karo jo code ko sach mein chahiye (jaise sizeof(void*) >= 4).
Exercise 3.2
Har ek ke liye result predict karo (pass / fail, aur compiler jo numeric value compute karta hai):
static_assert(sizeof(char) == 1, "P"); // (A)
static_assert(-1 < 0u, "Q"); // (B) tricky!
static_assert((1 << 4) == 16, "R"); // (C)Recall Solution
- (A) PASS.
sizeof(char)language ki definition se hamesha1hota hai. Value:1 == 1→1. - (B) FAIL. Literal
0uunsigned hai. Comparison mein-1unsigned mein convert ho jaata hai, ek bahut bada positive value ban jaata hai (sab bits set), isliye-1 < 0ufalse →0hai. Yeh "usual arithmetic conversions" ka gotcha hai, aurstatic_assertbuild refuse kar dega. Computed value:0. - (C) PASS.
1 << 4bit ko 4 places left shift karta hai =16.16 == 16→1.
Exercise 3.3
Kyun #error check sizeof(int) == 4 ke liye static_assert ko replace nahi kar sakta?
Recall Solution
#error preprocessor mein fire karta hai, jo compiler se pehle chalta hai aur sirf preprocessor tokens aur #if arithmetic macros/integer literals par samajhta hai. Iske paas types ka koi notion nahi hai, isliye yeh sizeof(int) evaluate nahi kar sakta. static_assert ek stage baad, compiler mein chalta hai, jo type sizes jaanta hai. Isliye size/enum checks static_assert mein jaate hain, #error mein nahi.
Level 4 — Synthesis
Exercise 4.1
Ek single static_assert design karo jo guarantee kare ki ek struct mein koi padding nahi hai, yeh check karke ki uska size uske members ke sizes ke sum ke barabar hai:
struct Point { short x; short y; }; // want sizeof == 4Assertion likho, phir ek platform batao jahan yeh legitimately fail ho sakta hai.
Recall Solution
static_assert(sizeof(struct Point) == sizeof(short) + sizeof(short),
"struct Point has unexpected padding");Typical machine par sizeof(short) == 2, isliye hum assert karte hain 4 == 4 → pass. Yeh ek aise platform par legitimately fail ho sakta hai jahan compiler alignment padding insert kare (jaise agar short alignment ne gap force kiya), jisse sizeof(struct Point) 4 se bada ho jaaye. Yahi woh surprise hai jo aap build time par pakadna chahte ho raw byte I/O karne se pehle struct par.
Exercise 4.2
Ek enum aur sizeof check ko ek guard mein combine karo jo fail ho agar bit-mask enum uint8_t mein fit hone se zyada badh jaaye.
#include <stdint.h>
enum Perm { P_READ = 1, P_WRITE = 2, P_EXEC = 4, P_ALL = 7 };Ek static_assert likho jo ensure kare ki P_ALL ek byte mein fit ho (value ≤ 255) aur uint8_t sach mein ek byte ho.
Recall Solution
static_assert(P_ALL <= 255 && sizeof(uint8_t) == 1,
"Perm mask must fit in a single uint8_t");P_ALL ek enum constant hai (7) → constant expression; sizeof(uint8_t) constant hai. Result: 7 <= 255 1 hai, sizeof(uint8_t) == 1 1 hai, 1 && 1 → 1 → pass. Agar koi baad mein P_SPECIAL = 256 add kare, aur P_ALL = 511 set kare, toh pehla half 0 ban jaata hai aur build ruk jaata hai.
Level 5 — Mastery
Exercise 5.1
Ek portable header snippet likho jo:
- C23 mein compile hone par
<assert.h>include kiye bina real C23 keywordstatic_assertuse kare, aur - C11/C17 ke under
_Static_assertpar fallback kare.
__STDC_VERSION__ macro use karo (201112L = C11, 202311L = C23).
Recall Solution
#if __STDC_VERSION__ >= 202311L
/* C23: static_assert is a keyword, message optional */
#define MY_SASSERT(cond, msg) static_assert(cond, msg)
#else
/* C11/C17: use the raw keyword so no header is required */
#define MY_SASSERT(cond, msg) _Static_assert(cond, msg)
#endif
MY_SASSERT(sizeof(int) >= 2, "int must hold at least 16 bits");Dono spellings ka matlab ek hi hai; hum sirf <assert.h> par depend hone se bachne ke liye branch karte hain aur is baat ka dhyan rakhte hain ki C23 ne message rule relax kiya. Dekho C11 vs C23 language features.
Exercise 5.2
Ek parser fixed on-disk layout ke records padhta hai. Aapko build time par guarantee karni hai ki:
RECORD_SIZE ek power of two hai, kam se kam sizeof(struct Header) hai, aur 4096 bytes ke ek PAGE ko evenly tile karta hai. Diya gaya hai:
#define RECORD_SIZE 64
#define PAGE 4096
struct Header { int magic; int len; }; /* assume sizeof == 8 */Ek static_assert likho jo teeno conditions enforce kare aur evaluate karo ki yeh pass hota hai ya nahi.
Recall Solution
static_assert(
(RECORD_SIZE & (RECORD_SIZE - 1)) == 0 && /* power of two */
RECORD_SIZE >= sizeof(struct Header) && /* holds a header */
(PAGE % RECORD_SIZE) == 0, /* tiles the page */
"RECORD_SIZE constraint violated");Evaluate karo:
- Power of two:
64 & 63=0✔ (64hai1000000₂, ek set bit). - Header hold karta hai:
64 >= 8→ true ✔. - Page tile karta hai:
4096 % 64=0✔ (4096 / 64 = 64).
Teeno 1 hain, isliye 1 && 1 && 1 → 1 → pass hota hai. RECORD_SIZE ko 100 par change karo aur ek ke alawa har clause fail ho jaata hai: 100 & 99 = 96 ≠ 0 → build ruk jaata hai.

Wrap-up recall
Upar ke solutions ke liye numeric checks verification block mein hain.