Concepts / Fundamental Types in C++

Fundamental Types in C++

Built-in types can be built from the fundamental types, the const modifier, and the declarator operators.

  • Programming

Predicting What a Size Query Prints

C++ gives every program a small set of built-in types that can be used without defining anything new. These are called fundamental types. Before we explain them, it helps to ask the computer a question about one of them and to predict the answer. The question is simple: how many bytes does a char occupy? Think about it before reading on, because the rest of this article is about what that number means and why it is not always the same everywhere.

What do you think happens?

What number does sizeof(char) produce in a C++ program?

  • 0

  • 1

  • 4

  • 8

Reveal answer
Answer:

1

sizeof(char) equals 1 by definition in C++. The size of char is the unit that other type sizes are measured against, and a char is typically an 8-bit byte.

Why Built-in Types Stay Close to Hardware

Imagine you need a language in which a programmer can write a fast program with almost no hidden cost, where every operation maps onto something the machine actually does. C++ begins from that requirement. Its built-in types and operations are rich, but they are deliberately low-level. They reflect the capabilities of conventional computer hardware directly and efficiently, so there is no runtime layer standing between the program and the machine.

A low-level foundation has a consequence. The built-in types do not give you high-level facilities that make advanced applications easy to write. Those facilities come from a second layer, a set of abstraction mechanisms that programmers use to build higher-level facilities themselves. Keep this two-layer picture in mind, because the connection between the layers is what the next section explains.

Built-in and User-Defined Types

Built-in types are the starting material. Abstraction mechanisms are the tools that turn that material into something larger. The source describes these mechanisms as a sophisticated set that C++ adds on top of the built-in types and operations. Their purpose is specific: they let programmers design and implement their own types, with suitable representations and operations, and they let other programmers use those types simply and elegantly once they exist. A type built this way is called a user-defined type. The source gives two names for this kind: classes and enumerations.

Built-in typesfundamental types, const,declarator operatorsAbstractionmechanismstools for designing newtypesUser-defined typesclasses and enumerationsaugmented byused to buildconstructed out of
How do built-in types sit at the bottom layer, and how do user-defined types and abstraction mechanisms get built on top of them?

The diagram shows three relationships. Built-in types are augmented by abstraction mechanisms. Those mechanisms are the means by which user-defined types are built. User-defined types are also constructed out of the built-in types, so the built-in layer stays the foundation even at the top of the stack. The standard library mainly consists of user-defined types, so it is a good place to see this layering at work once the built-in foundation is clear.

Building a Built-in Type from Three Ingredients

The definition of a built-in type reads like a recipe with three inputs. The first input is the set of fundamental types. The second is the const modifier, which marks a value as one that should not change. The third is the set of declarator operators, which shape how a declaration names and structures a type. A built-in type is whatever the language lets you form by combining these three inputs.

constconst modifier: valueshould not changeintfundamental typeapplied to
The declaration const int combines a fundamental type with the const modifier, which is one of the three ingredients.

Read a declaration like const int as a combination of parts rather than as one unbreakable word. Here the fundamental type int is combined with the const modifier, which is exactly the recipe the definition names. This example does not invent a new kind of type with its own operations. The source does not list every possible combination, so treat this as one illustration of the general principle rather than a complete catalogue.

The Five Fundamental Types

C++ provides five fundamental types used here: bool, char, int, double, and unsigned. Each one has a distinct job and holds a different kind of value. The table below pairs each type with the kind of value it holds.

TypeKind of value it holds
boolone of two values
chara single character
intwhole numbers that may be negative
doubledecimal numbers
unsignedwhole numbers that are never negative

The five fundamental types and the kind of value each one holds

The names already hint at the differences. A bool is a yes-or-no kind of value, a char holds one character, an int holds whole numbers with a sign, a double holds decimal numbers, and an unsigned holds whole numbers that cannot go below zero. Choosing the right type starts with asking which of these kinds of value your data actually is.

Fixed Size Sets the Range

A fundamental type is tied directly to what the hardware of the machine can do. Each one occupies a fixed amount of memory, and that fixed size limits the set of values the type can hold. A type that occupies more memory can distinguish more possible values, and a type that occupies less can distinguish fewer. So when you ask what range an int can hold, the honest first answer is the size of the int on the machine in question, because the range follows from the size.

1 byte8 bits, 2^8 = 256 patterns2 bytes16 bits, 2^16 = 65,536patterns
How does a type's bit count map to the number of distinct values it can hold?

The comparison above uses only the arithmetic of binary storage: each extra bit doubles the number of distinct patterns a type can store, so a 16-bit value has far more possible patterns than an 8-bit value. The source makes the general point that more memory means more distinguishable values. The exact range of a particular type on a particular machine still depends on its size there, which is why the next section introduces the sizeof operator as the way to ask.

Asking a Program with sizeof

The sizeof operator reports how many bytes a type occupies. Its result is a number you can print, compare, or use in calculations. The source gives two anchor values to remember: sizeof(char) equals 1, and sizeof(int) is often 4. The word often matters. A char is typically an 8-bit byte, and the sizes of other types are quoted in multiples of the size of a char. Because the size is implementation-defined, 4 for int is a common outcome rather than a rule the language guarantees on every machine.

cpp
Output
1
4
Notes on the code
  • sizeof(char) asks the program for the byte count of char
  • sizeof(int) asks the same question for int, whose result can vary by machine

Read the output as a fact about this program running on this machine. The first line is 1 on any conforming system, because sizeof(char) is defined as 1. The second line is 4 on many systems, but a different machine may print another number. The program does not tell you the range of int directly; it tells you the size, and the range follows from that size.

Worked example

Turning a sizeof Result into a Range Question

A program prints 4 for sizeof(int) on a machine. What does that tell you about the values an int can store there?

  1. 1
    Identify the size

    The result 4 means an int occupies 4 bytes on this machine.

  2. 2
    Connect size to distinguishable values

    A type that occupies more memory can distinguish more possible values, so the 4-byte size fixes how many distinct values an int can hold here.

  3. 3
    Avoid overgeneralizing

    Another machine might report a different size, so the 4-byte result describes this machine and should not be assumed for every system.

Result

On this machine, the int range is determined by its 4-byte size. Other machines may give a different size and therefore a different range.

Mistakes with Sizes and Ranges

  • Common mistake

    Assuming int is always 4 bytes

    What it looks like

    Writing code that stores a value assuming sizeof(int) is 4 everywhere

    Why it fails

    The size of a type is implementation-defined, so 4 is only often the outcome, not a guarantee on every machine.

    Do this instead

    Ask the program with sizeof when the size matters, rather than hard-coding the number.

  • Common mistake

    Thinking a type's range is fixed across all machines

    What it looks like

    Stating that an int always holds the same set of values regardless of platform

    Why it fails

    A fundamental type's fixed size is tied to the hardware, and that size determines its range, so the range can change with the machine.

    Do this instead

    Derive the range from the size on the machine in question.

  • Common mistake

    Treating unsigned and int as holding the same kind of value

    What it looks like

    Expecting an unsigned variable to hold a negative whole number

    Why it fails

    An unsigned holds whole numbers that are never negative, while an int holds whole numbers that may be negative.

    Do this instead

    Choose unsigned only when the value can never be negative, and int when negative values are possible.

  • Common mistake

    Confusing char with a number of arbitrary size

    What it looks like

    Assuming a char is wider than a byte because it holds characters

    Why it fails

    A char is typically an 8-bit byte, and sizeof(char) equals 1, which is the unit for other type sizes.

    Do this instead

    Treat char as one byte in size and use sizeof to check other types against it.

  • Common mistake

    Forgetting that sizeof reports bytes, not the number of values the type can hold

Checking Your Reading of Sizes

EASY

A colleague says that because sizeof(int) printed 4 on their laptop, every C++ program on every machine will also have a 4-byte int. Explain why this claim is not guaranteed, and describe what your program should do if the exact size matters.

Hints
  • Recall that the size of a type is implementation-defined.
  • The word often in the source signals a common outcome, not a universal rule.
  • sizeof is the tool for asking the program, not for guessing from another machine.

Key Takeaways

  • Built-in types are formed from the fundamental types, the const modifier, and the declarator operators, and they are deliberately low-level, close to conventional hardware.
  • User-defined types such as classes and enumerations are built with abstraction mechanisms on top of the built-in layer.
  • The five fundamental types are bool, char, int, double, and unsigned, each holding a different kind of value.
  • Each fundamental type has a fixed size tied to hardware, and that size determines its range; sizeof(char) is 1, and sizeof(int) is often 4, but the size is implementation-defined.

Related concepts

More concepts starting with F