Question
C++ Fundamental Type Sizes: What the Standard Guarantees About int, long, char, float, and double
Question
I want detailed information about the sizes of C++ fundamental types.
I understand that sizes can depend on the architecture (for example 16-bit, 32-bit, or 64-bit systems) and on the compiler. However, does the C++ standard define any guarantees for these types?
I am using Visual Studio 2008 on a 32-bit system, and I observe the following sizes:
char : 1 byte
short : 2 bytes
int : 4 bytes
long : 4 bytes
float : 4 bytes
double : 8 bytes
I would like reliable information about what the C++ standard says regarding the sizes of char, short, int, long, float, double, and other built-in types, and how those sizes can vary across compilers and architectures.
Short Answer
By the end of this page, you will understand what the C++ standard actually guarantees about fundamental type sizes, what it leaves implementation-defined, why int and long do not have fixed sizes, and how to write portable C++ code when exact widths matter.
Concept
In C++, the sizes of fundamental types are not fully fixed by the language standard. Instead, the standard defines:
- minimum guarantees
- relative ordering rules between integer types
- broad properties of floating-point types
- the rule that
charis always exactly 1 byte
The important idea is that in C++, a byte does not necessarily mean 8 bits. A byte is the size of char, and its number of bits is given by CHAR_BIT from <climits>.
Integer types
For the standard integer types, the language guarantees an ordering like this:
sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
More precisely, the standard guarantees that each type can represent at least a certain range:
signed char: at least-127to127short: at least to
Mental Model
Think of C++ fundamental types as container labels with minimum capacity, not exact box dimensions.
shortmeans: "a small integer type, at least this capable"intmeans: "the natural integer type for the machine"longmeans: "an integer type at least as capable asint"
The standard does not say, "This box must always be exactly 4 bytes wide." It says more like, "This box must hold at least this much, and these boxes must be ordered from no larger to no smaller."
So if you ask for an int, you are asking for a general-purpose integer type chosen by the implementation. If you ask for std::int32_t, you are asking for a box with exactly 32 bits, if the implementation provides it.
That is the key distinction:
- language types like
intare about general-purpose programming - fixed-width types like
std::int32_tare about exact storage requirements
Syntax and Examples
Checking type sizes in C++
You can inspect sizes with sizeof:
#include <iostream>
int main() {
std::cout << "char: " << sizeof(char) << "\n";
std::cout << "short: " << sizeof(short) << "\n";
std::cout << "int: " << sizeof(int) << "\n";
std::cout << "long: " << sizeof(long) << "\n";
std::cout << "long long: " << sizeof(long long) << "\n";
std::cout << "float: " << sizeof(float) << "\n";
std::cout << "double: " << sizeof(double) << "\n";
std::cout << "long double: " << sizeof(long double) << "\n";
}
Step by Step Execution
Example program
#include <iostream>
#include <climits>
int main() {
std::cout << sizeof(char) << "\n";
std::cout << sizeof(int) << "\n";
std::cout << CHAR_BIT << "\n";
}
What happens step by step
#include <iostream>makesstd::coutavailable.#include <climits>makes constants likeCHAR_BITavailable.- The program starts in
main(). sizeof(char)is evaluated.- This is always
1by definition in C++. - It means one byte.
- This is always
sizeof(int)is evaluated.- The compiler provides the actual size for the current platform.
- On many systems, this is
4, but the standard does not require that.
Real World Use Cases
Binary file formats
If you read or write binary files, exact widths matter. A file format may require a 32-bit integer or a 16-bit field. In that case, use fixed-width types like std::uint32_t.
Network protocols
Protocols often define packet fields with exact sizes. Assuming int is 32 bits can break communication on other systems.
Embedded systems
On small devices, int may not match desktop expectations. Code that assumes desktop sizes may fail or waste memory.
Cross-platform libraries
Portable libraries avoid hardcoding assumptions about long and int. They use standard limits, sizeof, and fixed-width types where needed.
Memory-sensitive applications
Sometimes developers choose smaller types to reduce memory usage in large arrays or data structures. To do that safely, they must know what the implementation guarantees.
Serialization and deserialization
When converting objects to bytes for storage or transmission, exact widths and layout rules become important. Using plain int in serialized formats is often a portability bug.
Real Codebase Usage
In real projects, developers usually follow a few practical rules.
1. Use int for ordinary arithmetic and loop counters
for (int i = 0; i < count; ++i) {
// work
}
Why? Because int is usually the implementation's natural general-purpose integer type.
2. Use fixed-width types for external data
#include <cstdint>
struct PacketHeader {
std::uint32_t length;
std::uint16_t type;
};
This is common in networking, storage, and APIs.
3. Use std::size_t for object sizes and indexing
std::size_t n = values.size();
This is the correct type for sizes returned by the standard library.
4. Use guard checks instead of assumptions
static_assert(sizeof(std::uint32_t) == , );
Common Mistakes
Mistake 1: Assuming int is always 32 bits
Broken example:
int userId = 2147483647;
This value fits on common systems, but the assumption that int is always 32 bits is not guaranteed by the standard.
Avoid it by using:
std::int32_t userId = 2147483647;
when exact width matters.
Mistake 2: Assuming long is always bigger than int
Broken assumption:
// Not necessarily larger than int on every system
long value = 10;
long is guaranteed to be at least as wide as int, but it may be the same size.
Mistake 3: Treating a byte as always 8 bits
Broken assumption:
int bits = sizeof() * ;
Comparisons
General-purpose types vs exact-width types
| Type choice | What it means | Portable for exact storage? | Common use |
|---|---|---|---|
int | Natural integer type | No | General arithmetic |
long | At least as wide as int | No | Platform-dependent integer work |
long long | At least 64 bits | Not exact width, but minimum guaranteed | Large integers |
std::int32_t | Exactly 32 bits | Yes, if provided | File formats, protocols |
std::uint64_t |
Cheat Sheet
Core guarantees
sizeof(char) == 1sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)sizeof(float) <= sizeof(double) <= sizeof(long double)- a byte is the size of
char - bits per byte are given by
CHAR_BIT
Minimum integer widths
short: at least 16 bitsint: at least 16 bitslong: at least 32 bitslong long: at least 64 bits
Important reminders
intis not guaranteed to be 32 bitslongis not guaranteed to be 64 bitscharis always 1 byte, but a byte is not guaranteed to be 8 bitschar,signed char, andunsigned charare distinct types
Useful headers
FAQ
Is int always 4 bytes in C++?
No. The standard only guarantees that int is at least 16 bits. Many modern systems use 4-byte int, but not all.
Is long always 8 bytes on 64-bit systems?
No. On 64-bit Linux and macOS, long is often 8 bytes. On 64-bit Windows, long is usually 4 bytes.
Why is sizeof(char) always 1?
Because C++ defines a byte as the size of char. That does not mean a byte must contain 8 bits.
How can I get an exact 32-bit integer in C++?
Use std::int32_t from <cstdint>.
How do I check type limits portably?
Use std::numeric_limits<T> from <limits> or constants such as INT_MAX from <climits>.
Is double always 8 bytes?
Often yes in practice, but the standard does not require that exact size on every implementation.
Mini Project
Description
Build a small C++ program that prints the sizes and limits of fundamental numeric types on your machine. This demonstrates the difference between what the language guarantees and what your compiler actually chooses for the current platform.
Goal
Create a tool that reports type sizes, bit widths, and numeric limits in a portable way.
Requirements
- Print the size of
char,short,int,long,long long,float,double, andlong double. - Print the number of bits in a byte using
CHAR_BIT. - Print the minimum and maximum values for at least
intandlong. - Show the size of one fixed-width type such as
std::int32_t. - Use standard library headers only.
Keep learning
Related questions
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.