Variables & Basic Types

Course 1 · Ch 2
Variables & Basic Types
Where C's type sizes come from a promise, not a guarantee

Chapter 1 showed C trusting the programmer with the toolchain itself. This chapter shows the same trust applied to something Rust and Go both nail down precisely: how big a number actually is.

Declaring Variables

int age = 25; float price = 19.99; char grade = 'A'; double pi = 3.14159265;

type name = value; — no let, no var, no inference. Every variable's type is written explicitly, every time.

The Basic Types

  • int — a whole number
  • float — single-precision floating point
  • double — double-precision floating point, the default for real work
  • char — a single byte, holding a small integer that's interpreted as a character (there is no separate "character" type underneath — char genuinely is a small integer)

sizeof and Why Type Sizes Aren't Fixed

This is the chapter's real subject. In Rust, i32 is exactly 32 bits, everywhere, by definition — the type's name states its size as a language guarantee. In C, the standard only guarantees minimums: int is guaranteed to be at least 16 bits, but is commonly 32 bits on today's platforms — "commonly," not "guaranteed."

printf("%zu\n", sizeof(int)); // commonly 4, not guaranteed printf("%zu\n", sizeof(char)); // always 1, by definition

Writing genuinely portable C — code that behaves identically across every platform — means never assuming int is exactly 4 bytes, something Rust or Go code never has to worry about at all.

Fixed-Width Types via <stdint.h>

C99 added exactly the guarantee Rust and Go bake in by default — opt-in, not automatic.

#include <stdint.h> int32_t exact32 = 100; // always exactly 32 bits, guaranteed uint64_t exact64 = 100; // always exactly 64 bits, unsigned

Signed vs. Unsigned

Every integer type has a signed (default) and unsigned variant. This distinction hides a genuine asymmetry worth flagging now, well before Course 3's Undefined Behavior chapter covers it in full: unsigned overflow is well-defined — it wraps around (UINT_MAX + 1 becomes 0). Signed overflow is undefined behavior — the standard makes no promise about what happens at all, not even wraparound.

ConceptRustC
Integer size guaranteei32/i64 — exact, by definitionint/long — minimum only, platform-dependent
Opt-in exact widthn/a — always exactint32_t/uint64_t via <stdint.h>
Unsigned overflowpanics in debug, wraps in releasealways wraps — well-defined
Signed overflowpanics in debug, wraps in releaseundefined behavior — no guarantee at all
sizeof is an operator, not a function
sizeof(int) looks like a function call, but sizeof is genuinely a compile-time operator — sizeof x (no parentheses) works too when applied directly to a variable. The parenthesized form is just the conventional style.
Signed overflow does not reliably wrap around
Many programmers assume signed integers wrap the same way unsigned ones do. They don't — signed overflow is undefined behavior, meaning the compiler is free to assume it never happens and optimize accordingly, sometimes producing results stranger than a simple wraparound. Course 3's Undefined Behavior chapter covers exactly why this matters in practice.

Coding Challenges

Challenge 1

Write a program that prints the sizeof int, char, float, double, and long on your system, one per line, using %zu format specifiers.

📄 View solution
Challenge 2

Declare an unsigned char variable, set it to 255, add 1 to it, and print the result. Explain what happened and why it's well-defined behavior rather than a bug.

📄 View solution
Challenge 3

Explain why int32_t from stdint.h is a genuinely different guarantee than plain int, and why Rust's i32 never needed an equivalent "opt-in exact width" type at all.

📄 View solution

Chapter 2 Quick Reference

  • int/float/double/char — explicit types, no inference
  • char is genuinely a small integer, not a distinct character type
  • The standard guarantees minimum sizes only — int is commonly 4 bytes, never guaranteed
  • <stdint.h>'s int32_t/uint64_t — opt-in, Rust/Go-style exact widths
  • Unsigned overflow — well-defined wraparound; signed overflow — undefined behavior, no guarantee
  • sizeof is an operator, not a function — parentheses are convention, not a requirement
  • Next chapter: operators, control flow, and C's historical lack of a true boolean type