Write an int into a union, read it back as bytes — and the answer depends on which machine you’re standing on. This question from our C Programming Quiz App is the rare one whose correct answer is “it depends”: it tests union type punning and endianness, the byte-order property that most C programmers first meet exactly here.
The Quiz Question
union U { int i; char c[4]; };
union U u;
u.i = 0x41424344;
printf("%c", u.c[0]);
What is printed by this code?
- A
- D
- Compile error
- Platform-dependent
The Correct Answer: Platform-Dependent
All members of a union share the same storage, so u.c[0] reads the first byte of the four bytes that hold 0x41424344. Which byte comes first is the machine’s endianness:
value 0x41424344 = bytes 0x41('A') 0x42('B') 0x43('C') 0x44('D')
little-endian (x86-64, ARM64): memory = 44 43 42 41 → c[0] = 'D'
big-endian (SPARC, s390x): memory = 41 42 43 44 → c[0] = 'A'
Little-endian machines store the least significant byte first. Both of our test platforms are little-endian, and both agree:
$ gcc -ansi -Wall -Wextra endian.c && ./a.out (x86-64 and ARM64) c[0] = D all bytes: D C B A
On a big-endian machine the same program prints A — we state that from the definition of byte order rather than a live run, since genuinely big-endian hardware is rare today (network byte order, s390x mainframes, some embedded cores). Since the output legitimately differs by platform, “platform-dependent” is the only defensible answer.
Why Each Wrong Answer Is Wrong
Why not “D”?
D is correct on the machines you probably own — every x86 and mainstream ARM system. But the question asks what the program prints, and C makes no promise about byte order. An answer that’s right on your laptop and wrong on a mainframe isn’t an answer; it’s an assumption. (This is the same discipline as the sizeof(pointer) question — know when your “fact” is really a platform detail.)
Why not “A”?
A is the big-endian result — and the intuition behind it is reasonable: “the first byte of 0x41424344 is 0x41″. That’s how humans write numbers, and how big-endian machines store them. Little-endian machines flip it, and they won the desktop.
Why not a compile error?
The union, the assignment, and the member read are all standard C. Reading a different member than was last written is explicitly sanctioned (C99 TC3 and later spell out that the bytes are reinterpreted as the new type) — the value you get is unspecified/implementation-defined territory, but the code is legal and warning-free on both compilers.
Type Punning, Legality, and Where This Bites
Reading u.c after writing u.i is called type punning — deliberately reinterpreting an object’s bytes as another type. Through a union it’s legal in C (and via char specifically it’s doubly safe, since char may alias anything); the union trick is C’s sanctioned alternative to pointer-cast punning, which can violate strict aliasing. What the language never promises is what the bytes mean — that’s the ABI’s business.
Endianness stops being trivia the moment bytes leave your machine: network protocols define big-endian (“network byte order” — hence htonl/ntohl), file formats pick one and document it, and code that fwrites raw structs bakes its host’s byte order into the file. The union-of-int-and-char[] pattern in this question is, in fact, the classic runtime endianness detector: u.i = 1; u.c[0] == 1 means little-endian. This question turns the detector into a puzzle.
Frequently Asked Questions
Is reading a different union member than was written legal in C?
Yes — the standard says the bytes of the stored value are reinterpreted as the type of the member you read. Legal, but the resulting value depends on the representation, which includes byte order.
What is the difference between little-endian and big-endian?
Little-endian stores the least significant byte at the lowest address (0x41424344 → 44 43 42 41 in memory); big-endian stores the most significant byte first (41 42 43 44). x86 and mainstream ARM are little-endian; network byte order is big-endian.
How can I check endianness at runtime in C?
Exactly the pattern in this question: store a known int in a union with a char array and inspect byte 0. u.i = 1; u.c[0] == 1 means little-endian. At compile time, gcc and clang define __BYTE_ORDER__.
Related Reading
- C Aptitude: Endianness and Pointer Arithmetic
- Struct Initialization in C – Members, Order, and Access
- Structures in C – Complete Guide
- C Aptitude Questions and Answers
Recommended Books
- The C Programming Language – Kernighan & Ritchie (India) | Amazon.com
- C Programming: A Modern Approach – K.N. King (India) | Amazon.com
This question is #119 in the C Programming Quiz App — 155 questions with explanations covering structs, unions, memory, and more.
Download on Google Play →