5.1.31 · D1 · Coding › C Programming › Compile-time assertions — static_assert
static_assert ek promise hai jo tum apne code ke baare mein karte ho, jise compiler check karta hai aur enforce karta hai — program exist karne se pehle hi . Agar promise false nikla, toh build ruk jaati hai — isliye pehle yeh samajhna zaroori hai ki "compiler", "constant", aur "value ka zero ya non-zero hona" actually matlab kya rakhte hain.
Parent note ki ek bhi line padhne se pehle, tumhare saamne symbols aur words ka ek dhera aata hai: static_assert, sizeof, enum, #define, &, &&, "constant expression", "compile time", "diagnostic". Yeh page har ek cheez ko scratch se , us order mein build karta hai jisme agle concept ke liye pichhla concept zaroor samajh aaya ho.
Is poore topic ki neenv ek cheez pe tikki hai — kab koi cheez hoti hai. Toh hum wahaan se shuru karte hain.
Definition Program ki zindagi ke do moment
Compile time = woh pal jab compiler naam ka tool tumhari text file padhta hai aur use machine instructions mein translate karta hai. Program abhi chal nahi raha — woh ek runnable cheez ke roop mein exist bhi nahi karta.
Run time = baad mein, jab koi insaan tayyar program pe double-click karta hai aur machine actually un instructions ko execute karti hai.
Figure Figure 1 — do clocks
Left (cyan zone) mein compiler tumhari .c text ko ek program file mein badalta hai. Right (amber zone) mein woh program chalta hai. Amber arrow follow karo: static_assert left side ka gate hai, jo kisi bhi program ke exist hone se pehle check hota hai; right side ka cyan assert note sirf runtime mein fire karta hai.
Intuition Yeh split kyun matter karta hai
Left side ka check program chalne par kuch bhi cost nahi karta, aur skip nahi kiya ja sakta , kyunki agar check fail ho toh simply koi program hi nahi hoga jo chale. Right side ka check har run mein time cost karta hai aur tabhi fire hota hai jab exactly woh line reach ho.
Related runtime tool: assert (runtime assertions) right clock pe rehta hai. static_assert uska left-clock cousin hai.
static_assert ka rule hai: "agar value zero hai, toh fail karo." Toh hume value ka matlab pakka karna hoga.
Definition Value, aur C mein truthiness
Value bas ek aisa number hai jo compiler compute karta hai. C mein classic sense mein koi alag "true/false" type nahi hota — instead:
Number 0 ka matlab false hota hai.
Koi bhi non-zero number (1, 2, −7, …) ka matlab true hota hai.
Intuition 0 = false kyun?
Ek light switch ko number ke roop mein socho: "off" naturally 0 hai, "on" hai "kuch current beh rahi hai" = zero nahi. C yehi borrow karta hai: kuch nahi / khali / off = 0 = false; kuch maujood = true.
Toh jab parent note kehta hai "agar condition zero (false) hai, toh compilation fail" — matlab compiler ek number compute karta hai, aur sirf exact value 0 hi stop trigger karti hai.
Comparisons aur sizeof se pehle, kisi bhi expression ki sabse basic ingredient woh plain number hota hai jo directly source mein likha ho. Uska ek naam hai.
Literal woh value hoti hai jo program ke text mein directly likhi ho , apne aap ke liye — use jaanne ke liye kuch compute ya lookup nahi karna padta. Examples:
integer literals : 4, 1024, 0 (aur 0xFF = 255 hexadecimal mein, 010 = 8 octal mein),
character literal : 'A' (jo actually andar se integer 65 hai),
string literal : "message" (woh text jo static_assert ke message ke liye use hota hai).
Intuition Literals yahaan kyun matter karte hain
Literal sabse pure possible compile-time constant hai: compiler 1024 padhta hai aur instantly value jaanta hai, bina koi program chalaye. Har constant expression aakhirkar literals (aur sizeofs, enums, #defines) ko operators ke saath combine karke banta hai.
static_assert ke andar condition usually sizeof(int) == 4 jaisi dikhti hai. Woh == asli kaam kar raha hai.
== operator
a == b ek sawaal hai: "kya yeh do numbers equal hain?" Pura expression khud ek number ban jaata hai :
yeh 1 (true) banta hai agar equal hain,
yeh 0 (false) banta hai agar nahi hain.
4 == 4 ⟶ 1 2 == 4 ⟶ 0
= aur == alag hain
Single = assign karta hai (ek variable mein value store karta hai). Double == compare karta hai. static_assert ke andar hamesha comparison == chahiye.
x = 4 ka matlab "4 ko x mein daalo"; x == 4 ka matlab "kya x 4 ke barabar hai?".
Toh static_assert(sizeof(int) == 4, "...") ka asli matlab hai: sizeof(int) == 4 se jo number bane use compute karo; agar woh number 0 hai, toh ruko.
Definition sizeof operator
sizeof(T) woh number deta hai jitne bytes ek T type ki value memory mein occupy karti hai. Byte memory ka sabse chhota addressable chunk hai — ise storage ka ek grid-square socho.
Figure Figure 2 — sizeof bytes count karta hai
Har type grid-squares (bytes) ki ek row hai. char ek square hai. int (typical machine pe) chaar squares hai, toh sizeof(int) 4 hai. Compiler yeh layout pehle se jaanta hai, isliye count compile time pe hi deta hai — koi program nahi chalna padta.
sizeof ek size_t deta hai (ek unsigned number)
sizeof jo number produce karta hai woh plain signed integer nahi hota — uska type ==size_t== hai, ek unsigned integer type (yeh kabhi negative nahi ho sakta, kyunki bytes mein size kabhi negative nahi hoti).
size_t ko signed values ke saath mix karna
Kyunki size_t unsigned hai, ise negative signed number se compare karna surprise de sakta hai: negative value pehle ek bahut bada unsigned number ban jaata hai. static_assert mein prefer karo sizeof(...) ko ek aur non-negative constant (jaise 4, ya dusra sizeof) se compare karna — exactly wahi jo parent ke examples karte hain.
sizeof kyun chahiye
static_assert ka classic use hai "mujhe assume hai ki int 4 bytes ka hai." Yeh assumption machine ke layout ke baare mein ek fact hai, chalne se pehle jaana ja sakta hai . sizeof us layout fact ko ek aisa number bana deta hai jise compiler compare kar sake. Puri treatment ke liye dekho sizeof operator .
sizeof hamesha compile-time constant nahi hota
C99 se, C ek variable-length array (VLA) allow karta hai jiska length runtime value hoti hai, jaise int a[n];. Aise array ke liye sizeof(a) run time pe compute hota hai aur constant expression nahi hota — toh yeh static_assert ke andar nahi ja sakta. Rule of thumb: sizeof kisi type pe ya fixed-size array pe compile-time constant hai; sizeof VLA pe nahi.
sizeof naapta hai ki type kitni badi hai. Uska close cousin _Alignof ek type ke baare mein alag compile-time fact naapता hai, aur yeh constant-expression list mein aata hai, toh hum ise abhi define karte hain.
_Alignof
Kisi type ki alignment woh byte spacing hai jis par machine insist karti hai ki uski values rakhi jaayein — ek int (4 bytes) usually aise address par honi chahiye jo 4 ka multiple ho. _Alignof(T) woh required spacing ek number ke roop mein deta hai (ek size_t). sizeof ki tarah, yeh machine ke layout se fix hota hai, toh compiler iska jawab compile time pe deta hai.
Intuition Yeh yahaan kyun aata hai
Kabhi kabhi tumhari assumption "yeh type kitni badi hai" nahi balki "kya yeh type mere trick ke liye kaafi strongly aligned hai" hoti hai — jaise static_assert(_Alignof(int) >= 4, "need 4-byte alignment"). Kyunki _Alignof(int) ek compile-time number hai, yeh static_assert condition ka ek legal ingredient hai, exactly sizeof ki tarah.
Definition Preprocessor aur #define
Compiler proper chalne se pehle, preprocessor naam ka pehla pass simple text substitution karta hai. #define BUFFER_SIZE 1024 use batata hai: "jab bhi aage BUFFER_SIZE word dikhe, text 1024 paste karo."
Toh jab compiler tumhara code dekhta hai, BUFFER_SIZE already 1024 ban chuka hota hai. Yeh use ek constant bana deta hai jo compiler static_assert ke andar use kar sakta hai.
#define koi variable nahi hai
#defined naam koi memory ka box nahi hai jo change ho sake. Yeh compilation se pehle ki gayi pure copy-paste hai. Yehi reason hai ki yeh compile-time check mein allowed hai — iske baare mein kuch bhi program run karne par depend nahi karta.
Common mistake Paste pitfalls: hamesha parenthesise karo
Kyunki #define blind text substitution hai, #define HALF 512+512 ko HALF * 2 mein daalne se paste hoga 512+512 * 2 = 1536, na ki 2048 — missing parentheses ne arithmetic badal di. Saath hi, ek macro ek expression mein kai baar expand ho sakta hai, toh unparenthesised macro silently us constant expression ko tod sakta hai jo tum static_assert ko dete ho. Fix: macro bodies ko parentheses mein wrap karo: #define HALF (512+512).
enum named integer constants ka ek group banata hai. enum { RED, GREEN, BLUE }; automatically RED = 0, GREEN = 1, BLUE = 2 bana deta hai (0 se count up karta hai). Tum custom start value pin bhi kar sakte ho, aur baad ke names wahaan se auto-increment karte hain: enum { A = 4, B, C }; deta hai A = 4, B = 5, C = 6. Ek single pinned constant bhi common hai: enum { COLOR_COUNT = 3 };.
Intuition Topic ko enums kyun chahiye
Enum values compile time pe fixed hoti hain, toh woh bhi static_assert ke andar legal hain. Parent ka "array aur COLOR_COUNT ko sync mein rakho" example exactly isliye kaam karta hai kyunki COLOR_COUNT ek compile-time constant hai, jo compile-time array length se comparable hai. Dekho Enumerations (enum) .
Parent ka power-of-two check (x & (x-1)) == 0 mein & use hota hai. Yeh logical "and" && nahi hai — woh alag sawaal ka jawab dete hain, toh hum dono define karte hain.
&
Har integer secretly binary digits (bits , har ek 0 ya 1) ki ek row hoti hai. a & b dono rows ko line up karta hai aur 1 sirf wahaan rakhta hai jahan dono mein 1 ho. Yeh bit-by-bit kaam karta hai aur ek naya number produce karta hai.
&&
a && b ek yes/no sawaal puchta hai: "kya a aur b dono true (non-zero) hain?" Yeh sirf 1 ya 0 produce karta hai — kabhi bit-pattern nahi. 2 && 4 is 1 (dono non-zero hain); 2 & 4 is 0 (unke paas koi common 1-bit nahi hai). & aur && dono static_assert ke andar allowed hain agar unke operands constant hon .
x & (x-1) == 0 power of two kyun detect karta hai
Amber squares 1-bits hain. Power of two (yahaan x = 8 ) mein exactly ek 1-bit hoti hai. 1 ghatane par woh bit off ho jaati hai aur har lower bit on ho jaati hai (7 ). Dono rows ko AND karne par 1 sirf wahaan rehta hai jahan dono mein ho — kahin nahi — toh result sab-zero hai. Yehi poora trick hai.
x kya hai, aur kya woh negative ho sakta hai?
Parent ke example mein x ek compile-time constant hai — ek #defined size jaise BUFFER_SIZE, na ki runtime variable (variable yahaan illegal hoga). Power-of-two trick assume karti hai ki x ek non-negative value hai: sizes kabhi negative nahi hote, toh yeh theek hai. Signed, negative number pe bit pattern (two's complement) x & (x-1) == 0 ko meaningless bana deta hai — ek aur reason ki ise sirf unsigned ya clearly-positive constants jaise buffer sizes pe apply karo.
Constant-expression list mein ek aur operator bhi allowed hai, ? :, jo shayad tumne abhi nahi dekha. Yeh C ka ek maatra aise operator hai jiske teen parts hote hain.
Definition Conditional (ternary) operator
cond ? a : b ek sawaal ki tarah padhta hai: "kya cond true (non-zero) hai? Agar haan, toh poori cheez a hai; agar nahi, toh b hai." Yeh ek test ke aadhar par do values mein se ek choose karta hai, aur result wahi value hai (ek if statement ki tarah nahi, jo value produce nahi karta).
3 > 2 ? 10 : 20 ⟶ 10 1 == 2 ? 10 : 20 ⟶ 20
Intuition Yeh yahaan kyun aata hai
Jab har part (cond, a, b) compile-time constant ho, toh compiler translation ke dauran answer pick kar sakta hai, toh poora ? : expression ek constant hai — static_assert ke andar legal. Jaise static_assert((sizeof(int) == 4 ? 1 : 0), "...") same size check likhne ka ek (clumsy) tarika hai.
Ab pehle ke har piece ko mila ke woh ek requirement banti hai jo static_assert ko govern karti hai.
Definition Constant expression
Constant expression koi bhi aisa expression hai jiska value compiler khud, bina program chalaye, poori tarah compute kar sake . Legal ingredients — upar sab define ho chuke hain — mein shamil hain:
literals (4, 1024, 'A'),
sizeof kisi type ya fixed-size array pe (nahi VLA pe),
_Alignof(T) — kisi type ki alignment requirement,
enum values aur #defined constants,
operators jaise ==, &, &&, +, -, aur conditional cond ? a : b.
Forbidden: koi bhi cheez jise program run karna pade — koi variable jo input se padha gaya ho, kisi function call ka result, ya sizeof kisi VLA pe.
Intuition Yaad rakhne wala ek sentence
static_assert sirf woh cheezein accept karta hai jo compile-time clock pe hain. Har symbol upar (literals, sizeof fixed sizes pe, _Alignof, enum, #define, ==, &, &&, ? :) compile-time hai — toh sab fair game hain. Runtime mein set hone wala variable nahi. Deep dive: Constant expressions in C .
Ab jab har ingredient exist karta hai, hum aakhirkar woh keyword define kar sakte hain jiske liye yeh poora page hai.
static_assert construct
static_assert ek constant expression aur (C11/C17 mein) ek message string leta hai, aur yeh karta hai: compiler expression evaluate karta hai; agar woh non-zero hai toh assertion gayab ho jaata hai (koi code emit nahi hota); agar zero hai toh compilation fail ho jaati hai aur message print hota hai. Tum ise wahaan rakh sakte ho jahan declaration allowed ho — file scope mein, struct ke andar, ya function body ke andar.
Definition "Diagnostic message" kya hota hai?
Diagnostic woh human-readable line hai jo compiler print karta hai jab kuch galat ho — wahi channel jo errors aur warnings ke liye use hota hai. Jo string tum static_assert ko dete ho woh tumhare words us channel mein inject ho jaate hain, toh ek cryptic failure ki jagah compiler exactly batata hai kyun: jaise
error: static assertion failed: "BUFFER_SIZE must be a power of two".
Yahaan ek clear message likhna hi woh cheez hai jo ek build failure ko agले programmer ke liye helpful instruction mein badal deti hai.
_Static_assert
C11/C17 mein actual language keyword _Static_assert (capital S, leading underscore — woh reserved style jo C nayi keywords ke liye use karta hai taaki tumhare apne names se kabhi clash na ho) spelled hota hai. Yeh macro spelling ki tarah exactly use hota hai:
_Static_assert(sizeof(int) == 4, "need 32-bit int");
#include <assert.h> likhne se tumhe friendlier alias static_assert milta hai, jise header simply _Static_assert ke liye #define kar deta hai. Toh neeche ki dono lines identical hain:
_Static_assert(E, "m"); static_assert(E, "m"); (after #include <assert.h> )
C23 mein static_assert ek real keyword ban gaya jise koi header nahi chahiye. Dekho Header <assert.h> aur C11 vs C23 language features .
Right side cover karo aur khud test karo.
static_assert kis clock pe (compile ya run) kaam karta hai?Compile time pe — program exist hone se pehle.
C mein kaun sa akela number false count hota hai? 0 (zero); har non-zero true hota hai.
C mein literal kya hota hai? Woh value jo directly source mein likhi ho aur apne aap ke liye khadi ho, jaise 4, 'A', "text".
Expression a == b kya evaluate karta hai? 1 agar equal hain, 0 agar nahi — yeh ek number ban jaata hai.
sizeof(T) kya return karta hai, aur kis type ka?Jitne bytes T occupy karta hai, unsigned size_t ke roop mein.
_Alignof(T) kya return karta hai?Type T ki required byte alignment (spacing), ek compile-time size_t.
sizeof kab constant expression nahi hota?Jab variable-length array (VLA) pe apply hota hai — uska size runtime value hai.
Compile time pe fixed array ke elements kaise count karte ho? sizeof(arr) / sizeof(arr[0]).
Kya #defined naam runtime variable hai? Nahi — yeh compile hone se pehle paste hone wala text hai, toh constant hai.
Unparenthesised #define kya pitfall cause karta hai? Blind text substitution arithmetic badal sakti hai; hamesha body ko parentheses mein wrap karo.
enum { A = 4, B, C } mein B aur C kya hain?B = 5 aur C = 6 — woh pinned start value se auto-increment karte hain.
& aur && mein kya fark hai?& numbers ko bit-by-bit combine karta hai; && ek single yes/no sawaal puchta hai "kya dono non-zero hain?".
cond ? a : b kya produce karta hai?a agar cond non-zero hai, warna b — yeh ek value yield karta hai.
x & (x - 1) == 0 kya test karta hai, aur x kya hona chahiye?Whether x power of two hai; x ek non-negative compile-time constant hona chahiye.
static_assert mein diagnostic message kya hota hai?Woh string jo compiler failure par print karta hai, explaining karta hai ki build kyun ruki.
C11 mein static_assert ke peeche raw keyword kya hai, aur kaise use hota hai? _Static_assert(expr, "msg") — identical usage; <assert.h> mein macro static_assert bas ise alias karta hai.
static_assert kahaan rakha ja sakta hai?Kahaan bhi jahan declaration allowed ho — file scope mein, struct ke andar, ya function ke andar.