Worked examples — Data types — char, short, int, long, float, double, size_t
The scenario matrix
Before working examples, let us enumerate the case classes. Think of this like listing every room in a house before we clean each one — we want to guarantee no room is skipped.
| Cell | Case class | What makes it tricky | Example |
|---|---|---|---|
| A | Signed value in range | baseline, no wrap | Ex 1 |
| B | Signed value above max (positive overflow) | wraps to negative | Ex 2 |
| C | Signed value below min (negative overflow) | wraps to positive | Ex 3 |
| D | Unsigned underflow (0 − 1) | wraps to the huge top value | Ex 4 |
| E | Zero / degenerate input | boundary, easy to mis-handle | Ex 5 |
| F | Limiting value (exactly MAX) | the edge itself, +1 tips over | Ex 6 |
| G | Float rounding (no finite binary form) | == fails |
Ex 7 |
| H | Signed ↔ unsigned mix | silent comparison flip | Ex 8 |
| I | Real-world word problem | pick the right type | Ex 9 |
| J | Exam twist (sizeof + promotion) | trap combining two rules | Ex 10 |
We use the term wrap to mean: when a value goes past the end of a type's range, it re-enters from the other end — like an odometer rolling from 999 back to 000. The figure below is the mental model for every integer example on this page.

Cell A — Signed value in range (baseline)
Cell B — Positive overflow (above max)
Cell C — Negative overflow (below min)
signed char c = -100;
c = c - 50; // -150, but the floor is -128
printf("%d\n", c);Forecast: is below . Which way does it wrap?
signed char: 8 bits, range , so , . Why this step? We reuse the wrap rule; we need and .- True value . Compute .
Why this step? In math,
modreturns a non-negative remainder: . - Add back : . Why this step? The formula repositions the wrapped remainder into the signed window.
Verify: , and ✅. Typical output 106. (Formally UB for signed — value is what a wrapping machine yields.)
Cell D — Unsigned underflow (0 − 1)
0u - 1 trap
unsigned int x = 0;
x = x - 1;
printf("%u\n", x);Forecast: subtracting 1 from 0 in an unsigned type — negative is impossible, so what appears?
unsigned intis 32 bits, range , and . Why this step? Underflow wraps around the top end; we need .- True value . Wrap: .
Why this step? Zero minus one rolls the odometer backwards past
000...0to the very top value (look at the left edge of figure s01).
Verify: ✅. Prints 4294967295. This is exactly why the countdown-loop bug from the parent note (size_t i; i >= 0) never terminates.
Cell E — Zero / degenerate input
sizeof(0)
long z = 0;
printf("%d\n", z == 0); // is it really zero?
printf("%zu\n", sizeof(z)); // how many bytes?Forecast: two outputs — a truth value and a byte count.
- Zero is inside every integer range (both signed and unsigned include 0), so no wrap, no rounding. Why this step? Zero is the safest possible value; it exposes no overflow behaviour — but it is the boundary that unsigned underflow (Ex 4) trips over.
z == 0is true → the==comparison yields1. Why this step? In C, a true relational expression has the integer value1.sizeof(long)on LP64 is 8, andsizeofreturns asize_t, printed with%zu. Why this step? sizeof Operator measures the storage, independent of the value stored — even zero occupies the full 8 bytes.
Verify: First line 1, second line 8 ✅. (The number stored is 0, but the box is still 8 bytes wide.)
Cell F — Limiting value (exactly MAX, then +1)
INT_MAX and stepping over
int m = 2147483647; // exactly INT_MAX
printf("%d\n", m); // still fine?
unsigned int um = 4294967295u; // exactly UINT_MAX
um = um + 1;
printf("%u\n", um);Forecast: the edge value prints cleanly; then +1 tips over.
INT_MAXis the largest representableint— exactly on the boundary, so it stores perfectly. Why this step? The limiting value is inside the range (the range is closed at the top), so no wrap yet.UINT_MAX, the largestunsigned int. Why this step? Same idea for the unsigned ceiling.um + 1 = 4294967296 = 2^{32}. Wrap: . Why this step? Stepping one past the top of the odometer lands back on0(right edge → left edge in figure s01).
Verify: Line 1 prints 2147483647; line 3 prints 0 because ✅.
Cell G — Float rounding (no finite binary form)
0.1 + 0.2 reveal
double d = 0.1 + 0.2;
printf("%.17f\n", d);
printf("%d\n", d == 0.3);Forecast: does the sum equal 0.3 exactly?
0.1in binary is a repeating fraction (like in decimal), sodoublestores the nearest 53-bit approximation. Why this step? Floating storage is finite; see IEEE-754 Floating Point for the 1/11/52 layout.- The stored
0.1is slightly above the true 0.1; same for0.2. Their sum's stored value is . Why this step? Two tiny rounding errors add up and don't cancel to exactly the stored0.3. 0.3on its own rounds to a different 53-bit pattern than the sum, sod == 0.3is false →0. Why this step?==compares bit patterns; two numbers "equal in decimal" can differ in bits.
Verify: The sum is and d == 0.3 gives 0 (false) ✅. Fix: compare fabs(d - 0.3) < 1e-9.

Cell H — Signed ↔ unsigned mix (silent comparison flip)
-1 > 1 becomes true
int s = -1;
unsigned int u = 1;
printf("%d\n", s < u); // is -1 less than 1?Forecast: surely is true (1)... or is it?
- In a comparison mixing
intandunsigned int, C converts both to unsigned. This rule comes from Type Conversion and Promotion. Why this step? The "usual arithmetic conversions" rankunsigned inthigher, so the signed operand is coerced. -1converted tounsigned intwraps to (same math as Ex 4). Why this step? There is no negative in unsigned; becomes the top value.- Now the comparison is , which is false →
0. Why this step? The huge wrapped value dwarfs1, flipping the intuitive result.
Verify: s < u evaluates to 0 (false) — the exact opposite of naive expectation ✅. Never compare signed to unsigned without an explicit cast.
Cell I — Real-world word problem (pick the type)
A program must store the size, in bytes, of a file that can be up to 5 gigabytes. Which type is safe, and what value does 5 GB hold?
Forecast: will a 32-bit int do the job?
- bytes. Why this step? We need the actual number to compare against type ceilings.
- A 32-bit signed
intmaxes at GB — too small; it would overflow (undefined behaviour). Why this step? , sointcannot represent it. - Use
size_t(unsigned, 64-bit on LP64, ceiling ). Its range comfortably holds . Why this step?size_tis the standard type for object/memory sizes — non-negative and wide enough. See Pointers and Addresses for why it tracks address width.
Verify: , which is but ✅. Answer: size_t, holding value 5368709120.
Cell J — Exam twist (sizeof + promotion trap)
sizeof('A') gotcha
printf("%zu %zu\n", sizeof('A'), sizeof(char));Forecast: both are one character — will both print 1?
sizeof(char)is guaranteed1by the standard — the only fixed size in C. Why this step? This is the baseline the trap plays against.- In C, a character constant like
'A'has typeint, notchar(a historical rule). Sosizeof('A') == sizeof(int). Why this step? The token'A'is promoted tointat the language level — this is the twist most students miss. - On LP64,
sizeof(int) == 4. So the two outputs differ. Why this step? The literal is anint(4 bytes) even though the character it denotes fits in 1 byte.
Verify: Prints 4 1 — sizeof('A') is 4 (int), sizeof(char) is 1 ✅. (In C++ the rules differ and sizeof('A') is 1; this trap is C-specific.)
Active Recall
Recall Cover the answers — one per matrix cell
unsigned char u = 250; u += 10;→ ? :::4(260 mod 256)signed char c = -100; c -= 50;→ ? :::106(−150 + 256), formally UBunsigned x = 0; x -= 1;→ ? :::4294967295()UINT_MAX + 1→ ? :::0( mod )0.1 + 0.2 == 0.3→ ? :::0(false, binary rounding)int -1 < unsigned 1→ ? :::0(false; −1 becomes huge)- Type for a 5 GB size → ? :::
size_t(holds5368709120) sizeof('A')in C → ? :::4('A'is anint)
Up past MAX → falls to the bottom. Down past MIN → jumps to the top. Zero minus one (unsigned) → the biggest value there is. Every wrap is just an odometer trip of size (figure s01).