Menu

C++ Data Types: int, double, char, bool, and More

A practical tour of C++'s fundamental data types - integers, floating-point, char, and bool - plus sizes, signed vs unsigned, literals and suffixes, overflow, and how to pick the right type.

This page includes runnable editors - edit, run, and see output instantly.

Why Types Matter in C++

When you declare a value with an explicit type like int age = 30;, that type is not just a label - it tells the compiler how many bytes to reserve, how to interpret those bytes, and which operations are legal. Get the type wrong and you can silently lose precision, overflow, or invoke undefined behavior.

C++ groups its built-in types into a few families: integers, floating-point numbers, a character type, and a boolean. Let's look at each, then at the rules that trip people up.

The Fundamental Types

Here is one of each core type in a single program. Notice the literal suffixes (L, f, u) and the single quotes on char:

A bool prints as 1 or 0 by default, not true/false. A char uses single quotes - 'A' is one character, while "A" (double quotes) is a string literal, a completely different type. Those two mistakes are extremely common early on.

Sizes Are Not Fixed

This is the biggest surprise coming from languages like Java. The C++ standard only guarantees minimum sizes and a relative ordering (shortintlonglong long). The actual size depends on your compiler and platform. Always check with sizeof:

On a typical 64-bit Linux build you'll see int = 4, long = 8. On 64-bit Windows, though, long is only 4 bytes. That portability gap is exactly why you should not write code that assumes long is 64-bit.

When you need an exact width, reach for the fixed-width integer types in <cstdint>:

Use int32_t/int64_t for file formats, network protocols, or anything that must behave identically across machines. Note the cast (int)a - streaming an 8-bit type prints it as a character, not a number, so cast it first.

Signed vs Unsigned

Every integer type comes in two flavors. A signed type can hold negatives; an unsigned type cannot, trading the negative range for a higher positive maximum. Plain int is signed by default.

Subtracting from an unsigned 0 wraps around to a huge positive number instead of going negative. This bites people constantly - especially with size_t (an unsigned type) returned by .size():

vector<int> v = {1, 2, 3};
// DANGER: v.size() is unsigned. If v is empty, v.size() - 1 wraps
// to a gigantic number and the loop runs nearly forever.
for (size_t i = 0; i <= v.size() - 1; i++) { /* ... */ }

Prefer i < v.size() (never <= size() - 1), or sidestep the whole issue with a range-based for loop.

Integer Overflow Is Undefined Behavior

Unlike unsigned wraparound (which is well-defined), signed integer overflow is undefined behavior in C++. The compiler is allowed to do anything - return garbage, optimize the check away, or crash:

The fix is the same as the overflow trap in any language: do the arithmetic in a wider type. Cast one operand to long long before the +, so the addition happens in 64 bits. Casting the result afterward is too late - the overflow already happened.

Picking the Right Type

For most code the defaults are fine: int for whole numbers, double for decimals. Reach for something else only when you have a reason.

TypeTypical sizeUse when
int32-bitThe default for whole numbers
long long64-bitValues past ~2 billion: timestamps, large counters
double64-bitThe default for decimals - good precision
float32-bitMemory-tight arrays where precision can suffer
bool1 byteA true/false flag
int32_t / int64_texactCross-platform formats, protocols, bit manipulation

A couple of gotchas to keep in mind. float has only about 7 significant decimal digits, so 0.1f + 0.2f is not exactly 0.3 - prefer double unless you truly need to save memory. And char may be signed or unsigned depending on the platform, so if you do arithmetic on raw bytes, spell out signed char or unsigned char.

Next: The auto Keyword

Writing out the type every time gets tedious, and sometimes the type is long or hard to name. C++ lets the compiler deduce it for you with the auto keyword - auto x = 42; makes x an int, and auto it = v.begin(); saves you from typing a verbose iterator type. The next page covers when auto makes code clearer and when it hides too much.

Frequently Asked Questions

What are the basic data types in C++?

The fundamental types are integers (short, int, long, long long), floating-point (float, double, long double), the character type char, and the boolean type bool. Each integer type can also be signed or unsigned. Everything else - std::string, arrays, your own classes - is built on top of these.

What is the difference between int and long in C++?

Both store whole numbers, but long is guaranteed to be at least as wide as int (often 64-bit on 64-bit platforms, but only 32-bit on Windows). The standard only fixes minimum sizes, so for a guaranteed width use the fixed-width types from <cstdint> like int32_t and int64_t.

How big is an int in C++?

The standard only guarantees int is at least 16 bits, but on virtually every modern desktop and server it is 32 bits. Because sizes are platform-dependent, never assume - print sizeof(int) to check, or use <cstdint> types like int32_t when you need an exact width.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED