Types Are Sizes

A variable is a patch of memory with a name. A type answers the two questions the compiler must settle before it can reserve that patch: how many bytes, and how should the bits be interpreted? Every C type is ultimately a size plus an interpretation, and this lesson gives you the standard's actual guarantees, which matter because exam papers and real machines routinely disagree about the numbers.

The Basic Types

ANSI C gives you four basic building blocks:

  • char: one byte, holding a character or a very small integer.
  • int: the machine's natural whole-number size.
  • float: a single-precision number with a fractional part.
  • double: a double-precision number, roughly twice float's accuracy. The default choice for real-number work, and the one this course uses.

int accepts modifiers that stretch or shrink it: short int, long int, and the modifiers may stand alone as short and long. Sign is a separate axis: short, int, and long are signed by default (they can hold negatives), or unsigned (zero and positives only, with double the positive range). Plain char is the exception — whether it is signed or unsigned is implementation-defined, and on this platform it is unsigned, which is why the ranges program below prints char range: 0 to 255. Combined, declarations read like unsigned long total; or short count;. The floating side has one extension of its own, long double, which appears later in this lesson.

The Three Families, in Exam Vocabulary

Textbooks and question papers sort C's types into three groups, and the words are worth having because questions are phrased in them:

  • Primary types, also called fundamental or basic: char, int, float, double, and void, together with the short, long, signed, and unsigned variants above. The language provides them.
  • Derived types: types built out of other types, namely arrays, pointers, and functions. Arrays arrive in chapter 7 and pointers in chapter 11.
  • User-defined types: type names you introduce yourself, with enum later in this chapter, struct and union in chapter 10, and typedef, which despite the name creates no new type at all, only a second name for an existing one.

void is the odd member of the primary group: a type with no values, whose job is to say "nothing here". You have been writing it since chapter 1 in int main(void), where it declares that main takes no parameters, and it appears again as the return type of a function that returns nothing. Functions are where it becomes useful, so chapter 9 is where it gets a proper treatment.

Measuring with sizeof

The sizeof operator reports the size in bytes of a type or an object. It is one of the 32 keywords, and it is your instrument for turning size talk into facts:

Run it. On this platform you will see char: 1, int: 4, long: 8, float: 4, double: 8. The %lu specifier prints an unsigned long; storing the sizeof result into an unsigned long variable first keeps the types matched.

What the Standard Actually Promises

Here is the part that separates a memorized answer from a correct one. ANSI C does not fix the size of int. It fixes minimums and an ordering:

  • char is exactly 1 byte by definition, and a byte is at least 8 bits.
  • int holds at least 16 bits; long holds at least 32.
  • The sizes never shrink as you go up: char is no larger than short, short no larger than int, int no larger than long.

Everything else is up to the machine and compiler. On the 16-bit compilers behind many textbooks, Turbo C above all, int is 2 bytes and ranges from -32768 to 32767. On this platform, and on essentially every modern desktop, int is 4 bytes with a range of about plus or minus 2.1 billion.

So when an exam asks "what is the size of int?", the honest answer is "at least 16 bits; commonly 2 bytes on old 16-bit compilers and 4 bytes on modern machines". Papers keyed to the textbook may expect "2 bytes"; now you know why, and you can give the expected number while writing programs that never depend on it.

Ranges, and the Header That Knows Them

Ranges follow from sizes. A 2-byte int spans -32768 to 32767; a 4-byte int spans -2147483648 to 2147483647; unsigned shifts the whole span above zero, so a 4-byte unsigned int reaches 4294967295. You do not memorize these per machine: the standard header <limits.h> defines them as symbolic constants.

Note %u for the unsigned value. What happens when arithmetic exceeds these limits is a story with two very different endings, one defined and one not, and it gets its own treatment in the operators chapter.

char Is an Integer in a Costume

char deserves a closer look: it holds a small integer that is usually interpreted as a character code. The character constant 'A' is just the integer 65 in the machine's character set. Both faces are printable:

%c shows the costume, %d shows the integer underneath. This dual nature is not a quirk to tolerate; the strings chapter and every character-processing exam question lean on it directly.

float vs double vs long double

Both hold fractional numbers, trading memory for precision: float gives about 6 reliable decimal digits in 4 bytes, double about 15 in 8 bytes. ANSI C's library and its conversion rules are built around double, literals like 7.5 are double, and the math functions take and return double, so the course default is simple: use double unless a specific reason says otherwise. Why floating-point numbers are approximate at all, and the surprises that causes, is a deep enough topic that it closes the course.

There is a third rung above double: long double, which the standard requires to be at least as precise as double and lets the implementation make better. It is the most machine-dependent type in the language. Compilers have shipped it as 8 bytes (identical to double), as an 80-bit format padded out to 12 or 16, and as a genuine 128-bit format, and the number of usable digits changes with each. <float.h> is the header that reports the truth for whatever you are compiling on, as DBL_DIG and LDBL_DIG, in the same spirit as <limits.h> for the integers.

Two details of using it are worth having now: a long double constant takes the suffix L, as in 1.25L, and printf needs %Lf rather than %f, because the argument is genuinely wider.

double: 8
long double: 16
wide = 1.25

Sixteen bytes here; do not carry that number to another machine. In practice long double earns its keep rarely, and reaching for it is usually a sign that the real problem is an algorithm losing precision rather than a type that is too narrow.

Key Takeaways

  • A type fixes a size in bytes and an interpretation of the bits; sizeof measures it.
  • The basic types are char, int, float, double, with short, long, signed, unsigned as integer modifiers.
  • Exam vocabulary sorts types into primary (char, int, float, double, void), derived (arrays, pointers, functions), and user-defined (enum, struct, union, typedef).
  • ANSI C guarantees minimums, not exact sizes: char is 1 byte, int at least 16 bits, long at least 32, never shrinking up the ladder. Old 16-bit compilers have 2-byte int; this platform has 4.
  • <limits.h> names each integer type's range: INT_MIN, INT_MAX, UINT_MAX, and friends; <float.h> does the same job for the floating types.
  • char is a small integer wearing a character costume: %c prints the character, %d the code.
  • Prefer double over float; the language is built around it. Above it sits long double, the most machine-dependent type in C, written with an L-suffixed constant and printed with %Lf.