5.1.24 · D3 · HinglishC Programming

Worked examplesUnions — overlapping memory

3,579 words16 min read↑ Read in English

5.1.24 · D3 · Coding › C Programming › Unions — overlapping memory

Yeh page drill ground hai. Parent note ne ideas build kiye — ek shared room, size = largest member, likhna baaki sab ko clobber kar deta hai. Yahaan hum har tarah ki situation jinhe union throw kar sakta hai grind karte hain, taaki koi exam question ya bug surprise na kar sake.

Shuru karne se pehle, vocabulary ka ek reminder, taaki koi cheez earned hone se pehle use na ho:


Scenario matrix

Har union problem inheen cells mein se kisi ek mein aata hai. Neeche ke examples us cell ke label ke saath hain jo woh cover karte hain — saath mein yeh poora grid fill karte hain.

Cell Case class Isme kya tricky hai
A Sizing — plain largest member size set karta hai
B Sizing — alignment padding largest member sabse strictly-aligned nahi hai
C Sizing — degenerate (array/struct member) ek member jo khud bada ya awkward hai
D Overwrite — same-size members ek likho, doosra padho (garbage / UB)
E Type punning — read raw bytes little-endian byte order matter karta hai
F Endianness flip big-endian alag answer deta hai
G Zero / default init = {0} sirf pehla member set karta hai
H Real-world word problem tagged union bookkeeping
I Exam-style twist nested union / char-array reinterpretation
J Bitfield union bits, bytes nahi, same word share karte hain

Figure 1 neeche bytes ke shared "room" ko draw karta hai jisme har member overlay hua hai, aur saare matrix cells list karta hai taaki ek nazar mein dekh sako ki har example kya vary karta hai. Notice karo ki sabse bada bar (double) woh hai jo room ki width set karta hai — yeh ek picture mein Cell A hai.

Figure — Unions — overlapping memory
Figure 1 — Bytes ka ek shared room; largest member iska width fix karta hai. Labels A–J un case classes ko tag karte hain jo neeche work kiye gaye hain.


Example 1 — Cell A: plain sizing

  1. Member sizes list karo. char=1, short=2, int=4. Yeh step kyun? Union ko worst case fit karna hai, isliye pehle sabse bada member jaanna zaroori hai — dekho sizeof operator.
  2. Maximum lo. . Yeh step kyun? Saare members offset 0 se start hote hain aur overlap karte hain, isliye room ko sirf sabse wide lodger jitna wide hona chahiye — sum nahi.
  3. Alignment check karo. int ko 4-byte alignment chahiye; 4 already 4 ka multiple hai, koi padding nahi lagti. Yeh step kyun? Final size strictest member ki alignment ka multiple hona chahiye taaki unions ki arrays lined up rahein (dekho Memory alignment and padding).

Answer: sizeof(union Small) == 4.

Verify: Agar yeh struct hoti, to size kam se kam hoti (padded to 8). Union ka us sum se chhota hona overlap confirm karta hai. ✓


Example 2 — Cell B: alignment padding (yeh sneaky wala hai)

  1. Sabse bada member dhundo. buf = 10 bytes, int = 4 bytes. Largest = 10. Yeh step kyun? Same rule: sabse bade lodger ke liye room reserve karo.
  2. Strictest alignment dhundo. int ko alignment 4 chahiye. char[10] ko alignment 1 chahiye. Strictest = 4. Yeh step kyun? Poori union ko apne strictest member ke aligned hona chahiye, kyunki compiler unions ko array mein back-to-back rakh sakta hai.
  3. Size ko 4 ke multiple tak round up karo. 10, 4 ka multiple nahi hai. Round up: . Yeh step kyun? Yeh parent ke formula ka step hai. Iske bina, array ki next union apne int ke liye misaligned address par start hogi.

Answer: sizeof(union Pad) == 12, 10 nahi.

Verify: , ka sabse chhota multiple hai jo ho. ✓, aur ✓.


Example 3 — Cell C: union ke andar chhupa ek struct

  1. Struct member ko size karo. Teen shorts of 2 bytes each, saare 2-aligned, bina gaps ke pack: . Dekho Structs — separate memory for each member. Yeh step kyun? Ek member khud ek compound type ho sakta hai — compare karne se pehle hume uski full size jaanni hai.
  2. Members compare karo. int=4, struct t=6. Largest = 6. Yeh step kyun? Struct yahaan worst case hai, isliye yeh width set karta hai.
  3. Alignment. Saare members mein strictest alignment: int 4 chahta hai, har short 2 chahta hai → strictest hai 4. 6 ko 4 ke multiple tak round up karo → 8. Yeh step kyun? Same padding rule jaise Example 2 mein; 6, 4 ka multiple nahi hai.

Answer: sizeof(union Wrap) == 8.

Verify: , ka sabse chhota multiple hai jo ho. ✓.


Example 4 — Cell D: same-size members ka overwrite

  1. Dono members same 4 bytes share karte hain. u.f = 2.0f likhne se woh bytes 2.0 ke float bit pattern se overwrite ho jaate hain. Yeh step kyun? Yahi union ka poora point hai — ek room. Int chala gaya.
  2. Standard caveat note karo. u.f likhne ke baad u.i padhna C standard ke according undefined behavior hai (last written member f hai, aur int character type nahi hai). Practice mein mainstream compilers bytes ko dikhaye gaye anusaar reinterpret karte hain, lekin portable code mein iska bharosa mat karo — agar truly bits chahiye to memcpy use karo. Yeh step kyun? Yeh reviewer-critical nuance hai: non-character member se type punning UB hai, guaranteed nahi. Dekho Type punning and bit-level reinterpretation.
  3. 2.0f ka float bit pattern dhundo (IEEE-754 single precision). . Sign=0, exponent field , mantissa = 0. Bits: 0 10000000 00000000000000000000 . Yeh step kyun? Typical compilers par, u.i padhne se exactly yeh bits ek signed integer ke roop mein padhte hain — koi arithmetic conversion nahi.
  4. 0x40000000 ko int ki tarah interpret karo. . Yeh step kyun? High nibble 4 top byte mein hai; hex convert karne se decimal int milta hai.

Answer: ek typical little-endian compiler par u.i 1073741824 print karta hai, NOT 1 aur NOT 2 — lekin formally yeh read UB hai.

Verify: . Yeh raw reinterpretation hai, exactly woh mistake jiske baare mein parent note warn karta hai — union koi converter nahi hai.


Example 5 — Cell E: little-endian par type punning

Figure 2 chaar bytes ko b[0]b[3] slots mein unke offsets ke saath lay out karta hai, aur yellow arrow mark karta hai ki least significant byte (0x44) kahaan land karta hai. Steps ko us picture ke against padho — arrow poora rule hai.

Figure — Unions — overlapping memory
Figure 2 — 0x11223344 ka little-endian layout: least significant byte 0x44 offset 0 par hai (b[0]), most significant 0x11 offset 3 par.

  1. Int ko value se bytes mein split karo. Most significant byte 0x11, phir 0x22, 0x33, least significant byte 0x44. Yeh step kyun? Har unsigned char slot exactly ek byte hold karta hai; hume jaanna hai ki kaun sa value kahaan land karta hai.
  2. Little-endian apply karo: least significant byte → lowest offset. To b[0] (offset 0) ko 0x44 milta hai, aur b[3] ko 0x11. Kyunki hum unsigned char se padhte hain, yeh standard ke anusaar fully defined hai — bytes inspect karne ka legal tarika. Yeh step kyun? Little-endian, by definition, least significant byte pehle rakhta hai. Yeh Figure 2 mein arrow hai.

Answer: b[0]=0x44, b[1]=0x33, b[2]=0x22, b[3]=0x11.

Verify: Little-endian reassemble: ✓.


Example 6 — Cell F: same code big-endian par

  1. Big-endian most significant byte ko lowest offset par rakhta hai. Yeh step kyun? Big-endian, little-endian ka mirror hai; highest-weight byte pehle jaata hai.
  2. Isliye b[0] = 0x11, b[3] = 0x44. Yeh step kyun? Byte ordering ka direct consequence — yahi reason hai type punning non-portable hai (dekho Endianness — byte order).

Answer: big-endian b[0]=0x11 (vs little-endian 0x44 Example 5 mein).

Verify: Bytes 11 22 33 44 ka big-endian read = ✓. Value identical hai; sirf byte layout alag hai.


Example 7 — Cell G: zero / default initialization

  1. {0} sirf pehle member d.i ko 0 se initialize karta hai. Yeh step kyun? Upar restate kiye gaye rule ke anusaar, union ka brace-initializer sirf first-listed member d.i ko touch karta hai.
  2. Lekin saare members same 4 bytes share karte hain. d.i = 0 set karne se chaar zero bytes 00 00 00 00 likhte hain. Yeh step kyun? Kyunki yeh overlap karte hain, int ko zero karna shared storage ko har member ke liye zero kar deta hai — isliye yahaan "sirf pehla member" rule sab members ke liye bytes zero kar deta hai aise hi.
  3. d.f padho: bit pattern 0x00000000 float ke roop mein exactly +0.0 hai. Yeh step kyun? IEEE-754: all-zero bits = positive zero. To yahaan d.f padhne se 0.0 milta hai (formally abhi bhi non-char read UB hai, lekin value IEEE machines par deterministic hai).

Answer: d.i 0 print karta hai, d.f 0.000000 print karta hai.

Verify: Float bits 0x00000000 = ✓. Caution: yeh sirf isliye kaam karta hai kyunki 0 ke saare bits zero hain — = {1} ke saath, d.f garbage hoga (0x00000001 = ek tiny denormal ≈ , 1.0 nahi).


Example 8 — Cell H: real-world tagged union

  1. Value AUR tag saath mein set karo.
    struct Setting s;
    s.v.n = 42;
    s.tag = COUNT;
    Yeh step kyun? Union ko yaad nahi ki kaunsa member live hai — enum tag tumhara bookkeeping hai.
  2. Sirf woh member padho jo tag name karta hai.
    if (s.tag == COUNT) printf("%d\n", s.v.n);   // prints 42
    else                printf("%s\n", s.v.text);
    Yeh step kyun? s.v.text padhna jab n live ho to integer 42 (0x2A) ko pointer address ki tarah treat karega — undefined behavior aur almost certainly ek crash. Tag yeh prevent karta hai by ensuring tum sirf last-written member padhte ho.

Answer: tag == COUNT ke saath, program safely 42 print karta hai; yahaan .text padhna undefined hai aur likely segfault deta hai.

Verify: s.v.n = 42 bytes for 42 store karta hai; tag hume int branch par route karta hai → 42. Bookkeeping hi hai jo ise safe banata hai, exactly jaisa parent ki tagged-union pattern require karta hai.


Example 9 — Cell I: exam twist — nested reinterpret

  1. Bytes lay out karo. c[0]=0x41 offset 0 par, c[1]=0x42 offset 1 par. (Humne char se likha, isliye woh byte values guaranteed hain.) Yeh step kyun? Humne har byte ko individually char array se likha, isliye pair ko short ke roop mein reinterpret karne se pehle hume exactly pata hai ki kaun sa byte value kis offset par hai. Character type se raw bytes padhna hamesha defined hai, isliye yeh layout trustworthy hai.
  2. unsigned short (2 bytes) ke roop mein little-endian par padho. Lowest offset (offset 0, value 0x41) ka byte short ka least significant byte hai; offset 1 (0x42) ka byte most significant hai. To short ki value hai . Yeh step kyun? Little-endian, by definition, least significant byte ko lowest address par rakhta hai — to offset 0 low half supply karta hai aur offset 1 high half jab do bytes ek 16-bit number mein assemble hote hain.
  3. Number compute karo. aur , isliye . Hex mein yeh 0x4241 hai. Yeh step kyun? High-byte plus low-byte reassemble karna do stored bytes ko ek single value mein turn karta hai jo %u read print karta hai.

Answer: u.s little-endian par 16961 (0x4241) print karta hai. (Big-endian par, offset 0 high byte hoga, 0x4142 = 16706 dega.)

Verify: ✓. Big-endian check: ✓.


Example 10 — Cell J: ek bitfield union

  1. Layout samjho. raw 1 byte (8 bits) hai. Struct ready(1) + error(1) + mode(2) + unused(4) = 8 bits ko same byte mein pack karta hai. sizeof(union Status) == 1. Yeh step kyun? Dono members same storage overlap karte hain — union rule abhi bhi hold karta hai, lekin ab bits line up karte hain, poore bytes nahi. Size = largest member = 1 byte.
  2. Raw byte likho. st.raw = 0x0D = binary 0000 1101. Ek typical little-endian compiler par, bitfields least significant bit se upar fill hote hain. Yeh step kyun? To bit 0 ( place) ready hai, bit 1 error hai, bits 2–3 mode hain. Bitfields ka bit ordering implementation-defined hai — yeh common layout hai, aur reason hai bitfield-punning non-portable hai.
  3. 0000 1101 se har field extract karo.
    • bit 0 = 1 → ready = 1
    • bit 1 = 0 → error = 0
    • bits 2–3 = 11 = 3 → mode = 3
    • bits 4–7 = 0000unused = 0 Yeh step kyun? Har field sirf apne bits pull out karta hai; mode ek 2-bit field hai isliye woh 0–3 hold kar sakta hai.

Answer: ready = 1, error = 0, mode = 3.

Verify: Reassemble: ✓. Bits raw byte reproduce karte hain, overlap confirm karta hai.

Caveat: Bitfield bit-order (kaun sa end pehle fill hota hai) aur storage units ka straddling implementation-defined hai — is pattern ko platform-specific treat karo, exactly byte-level type punning ki tarah.


Matrix coverage check

Recall Kaun se example ne kaun sa cell fill kiya?

A → Ex 1 ::: plain largest-member sizing (4) B → Ex 2 ::: alignment padding, 10 rounds to 12 C → Ex 3 ::: union ke andar struct member, 6 rounds to 8 D → Ex 4 ::: same-size overwrite 1073741824 deta hai (formally UB) E → Ex 5 ::: 0x11223344 ka little-endian byte order (char read = legal) F → Ex 6 ::: big-endian b[0] ko 0x11 kar deta hai G → Ex 7 ::: {0} pehla member zero karta hai → 0.0 float H → Ex 8 ::: tagged union safe read = 42 I → Ex 9 ::: nested char/short reinterpret = 16961 J → Ex 10 ::: bitfield union, raw 0x0D → ready 1, error 0, mode 3


Connections

  • Unions — overlapping memory (parent)
  • sizeof operator — sizing rule
  • Memory alignment and padding — round-up step
  • Endianness — byte order — Examples 5, 6, 9
  • Type punning and bit-level reinterpretation — Examples 4, 10 aur UB nuance
  • Structs — separate memory for each member — Examples 3, 10
  • Enums — Example 8 mein tag