Worked examples — Type sizes — sizeof, platform dependency, stdint.h (int32_t etc.)
This page is the "hands dirty" companion to Type sizes — sizeof, platform dependency, stdint.h (int32_t etc.). We will walk through every kind of situation the topic can throw at you: reading sizeof, the platform split, the overflow edge, the degenerate zero-width cases, a real network word-problem, and a nasty exam twist. Each example first asks you to guess, then shows every step with a reason, then verifies the number.
Before we start, one reminder in plain words: a byte here means "one char", and sizeof is a ruler that measures how many of those char-slots a thing takes. Nothing below assumes you already trust any size — we compute each from the rule that gave it.
The scenario matrix
Every worked example below is tagged with the cell of this matrix it covers. Together they touch every cell.
| Cell | What makes it different | Covered by |
|---|---|---|
| A. Basic measure | Read a size straight from sizeof on one known ABI |
Ex 1 |
| B. Platform split | Same type, different answer on LP64 vs LLP64 vs 16-bit | Ex 2 |
| C. Signed max/min | Largest & smallest value that fits (both signs) | Ex 3 |
| D. Unsigned wrap (limiting value) | Value at the very edge, and one step past it | Ex 4 |
| E. Zero / degenerate input | Empty array, sizeof of a zero-length-ish thing, sizeof(char) |
Ex 5 |
| F. Array length trick + decay trap | sizeof arr / sizeof arr[0] working vs silently broken |
Ex 6 |
| G. Real-world word problem | Design a packet struct with fixed widths | Ex 7 |
| H. Exam twist | A mixed signed/unsigned comparison that surprises everyone | Ex 8 |

The picture above lays the same eight cells on a number line of "how many bits" so you can see where each example lives: the small toy-computer end (16-bit), the mainstream middle (32-bit), and the wide end (64-bit).
Ex 1 — Cell A: Basic measure
Steps.
sizeof(char)is 1. Why this step? Because the standard definessizeofto count in units ofchar. Acharis onecharwide — always, on every machine. This is the one size you never have to look up.sizeof(int)on LP64 is 4. Why this step? The standard only promisesint≥ 16 bits. LP64 (Linux/macOS 64-bit) chooses 32 bits = bytes. We read this from the ABI table, not from a guess.sizeof(double)is 8. Why this step? An IEEE-754 double-precision float is 64 bits by design; bytes. This is stable across the mainstream ABIs.
Answer: 1 4 8.
Ex 2 — Cell B: The platform split
Steps.
- LP64 →
longis 8. Why this step? "LP64" literally means Long and Pointer are 64-bit. . - LLP64 →
longis 4. Why this step? "LLP64" means only Long-Long and Pointer are 64-bit; plainlongstays 32-bit. . This is the killer detail from the parent note. - 16-bit DOS →
longis 4. Why this step? Old 16-bitintwas 2 bytes, butlongstill had to satisfy the "≥ 32 bits" floor, so it was 4.
Answer: 8, 4, 4.

The figure shows the three memory boxes side by side: notice the LP64 box is twice as wide as the LLP64 box for the identical type name long. That visual mismatch is exactly the bug that bites cross-platform code.
Ex 3 — Cell C: Signed max and min
Steps.
- Count the patterns: 16 switches → distinct bit patterns. Why this step? Every bit is an independent on/off switch; each doubles the count, giving . This is the from-scratch derivation the parent used.
- Split for signed two's complement: half go to negatives, half to non-negatives. Range with . Why this step? The top bit acts as a sign region; the patterns split into negative and non-negative (which includes zero). See Two's complement & integer overflow for why the negatives get the exact half they do.
- Plug in: max , min . Why this step? The non-negative side spends one pattern on zero, so its top is ; the negative side has no zero to spend, so it reaches one further, to . They are not symmetric — there is one more negative than positive.
Answer: max 32767, min -32768.
Ex 4 — Cell D: Unsigned wrap at the limiting value
Steps.
- Range of
uint8_t: . Why this step? Unsigned counts from 0, so the top is . is sitting exactly on the ceiling. - Compute — but 256 needs a 9th bit, which does not exist in 8 bits. Why this step? We must check whether the mathematical result still fits; it does not, so the language rule for unsigned takes over.
- Unsigned overflow wraps modulo : result .
Why this step? The C standard defines unsigned arithmetic as arithmetic modulo — the extra high bit is simply discarded, like an odometer rolling from 999 to 000. (Careful: because of Integer promotion & usual arithmetic conversions,
x + 1is first computed asint, giving 256, then the assignment back touint8_tperforms the modulo. The final stored value is still 0.)
Answer: 0.
Ex 5 — Cell E: Zero / degenerate inputs
Steps.
- (a)
sizeof(char)is 1, by definition, forever. Why this step?sizeofmeasures in units ofchar, socharmeasures 1 of itself. Even on a hypothetical machine where acharis 9 or 16 bits,sizeof(char)is still 1 — it counts chars, not bits. - (b) A zero-length array has 0 elements × element-size = 0 bytes, so
sizeof ais 0 on compilers that allow it. Why this step? Total size = count × per-element size = . This is the degenerate "empty ruler" case — it multiplies down to nothing. - (c) An empty struct is not legal in standard C (it is in C++, where
sizeofwould be 1). In C you must give a struct at least one member. Why this step? The scenario matrix demands we cover the illegal degenerate input too, not just the small one — the correct answer here is "this doesn't compile", not a number.
Answers: (a) 1; (b) 0; (c) compile error in standard C.
Ex 6 — Cell F: Array-length trick and the decay trap
Steps.
- In
main:ais a real array of 10int.sizeof(a) = 10 × 4 = 40,sizeof(a[0]) = 4. Why this step?agenuinely occupies 40 contiguous bytes, and the ruler sees all of them. - Divide: . Correct element count. Why this step? Total bytes ÷ bytes-per-element = number of elements — a size-independent way to get length.
- In
f: the parameterint arr[]is a lie — C rewrites it toint *arr. Sosizeof(arr)is the size of a pointer = 8 on LP64, andsizeof(arr[0])is still 4. Why this step? Arrays passed to functions decay to pointers — see Pointers and array decay. The array's length is not carried along; only its first address is. - Divide: . Wrong — it is not 10. Why this step? The trick silently returns "pointer-size ÷ int-size", a meaningless 2, because the array's true length is gone. Fix: pass the length as a separate argument.
Answers: in main: 10, in f: 2 (on LP64).
Ex 7 — Cell G: Real-world word problem (packet struct)
Steps.
- Port range 0–65535 = → needs exactly 16 unsigned bits →
uint16_t(2 bytes). Why this step? , so 16 unsigned bits fit it perfectly; a smalleruint8_t(max 255) can't hold a port. - IPv4 address = 32-bit number →
uint32_t(4 bytes). Why this step? An IPv4 address is defined as exactly 32 bits (four octets). Fixed width guarantees both machines lay the same 4 bytes. - Timestamp, possibly large and negative →
int64_t(8 bytes). Why this step? Negative needs signed; "large" (e.g. Unix nanoseconds) overflows 32 bits, so we choose 64. - Add the data sizes: bytes.
Why this step? We sum the guaranteed widths. Every platform agrees on this data total because every field is fixed-width — the whole reason we avoided
int/long.
Answer: struct with uint16_t, uint32_t, int64_t; 14 bytes of data.
Ex 8 — Cell H: The exam twist (signed vs unsigned compare)
Steps.
- Spot the mixed types:
ais signedint,bisunsigned int. C must convert them to a common type before comparing. Why this step? Comparison needs both operands the same type; C applies the usual arithmetic conversions — see Integer promotion & usual arithmetic conversions. - The rule: when signed and unsigned
intmeet (same rank), the signed operand is converted to unsigned. Why this step? Unsigned "wins" at equal rank. Soa = -1is reinterpreted as an unsigned value. - Convert to
unsigned int(32 bits) modulo : . Why this step? Two's-complement all-ones is ; converting a negative to unsigned adds until it's in range. Soabecomes a huge number. - Compare ? False. So the
elseruns. Why this step? After conversion the comparison is between two unsigned values, and is not less than .
Answer: prints not less — the surprising branch.
Recall — cover the whole matrix
Recall Which cell does each idea live in?
Basic read → A. Same type, different size across ABIs → B. Signed max/min asymmetry → C. Unsigned edge wrap → D. Empty/illegal degenerate → E. Length trick vs decay → F. Packet design → G. Signed/unsigned compare surprise → H.
Recall Why does Ex 8 not print "less"?
The signed -1 is converted to unsigned (becomes ) before the comparison, so it is larger than 1, not smaller.
Recall Why is
int16_t min -32768 but max only 32767?
Two's complement has one more negative than positive: , because the non-negative side must spend one pattern on zero.
Connections
- Type sizes — sizeof, platform dependency, stdint.h (int32_t etc.) (parent)
- Two's complement & integer overflow
- Integer promotion & usual arithmetic conversions
- Pointers and array decay
- Struct padding & alignment
- Endianness & serializing data
- printf format specifiers
- size_t and ptrdiff_t