Language[lang]
Data types in C++: int, double, char, bool and more
- Section
- Language [lang]
- Standard
- C++17
- Compilers
- MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2, Clang 23.1 (libc++)
- Published
- Length
- 7 min read
In this answer6 clauses
- 1What are the basic data types in C++?
- 2How do you check the size and range of a type on your machine?
- 3Signed or unsigned, and what happens on overflow?
- 4When does the exact size matter? (int32_t and friends)
- 5What type does auto pick, and what do suffixes like
5umean? - 5.1Why does
int n{3.7}not compile? - 6Which C++ data type should you use?
Abstract
C++ data types say what a variable holds and how much memory it takes: int for whole numbers, double for decimals, char for one character, bool for true or false, and std::string for text. The standard sets only minimum sizes. MSVC, Clang and GCC on 64-bit Windows and Linux make int 4 bytes and double 8, while long is 4 bytes on Windows and 8 on Linux; sizeof and std::numeric_limits print the real size and range.

C++ data types say what kind of value a variable holds and how much memory it takes. The basic ones are int for whole numbers, double for decimals, char for one character and bool for true or false; text goes in a std::string. The standard sets only minimum sizes, so exact sizes depend on the compiler and the platform.
One variable of each, printed with std::cout:
#include <iostream>
#include <string>
int main() {
int age = 36; // a whole number
double height = 1.72; // a number with a decimal point
char grade = 'A'; // one character
bool is_member = true; // true or false
std::string name = "Ada"; // text, from the standard library
std::cout << std::boolalpha; // print bool as true/false, not 1/0
std::cout << "name: " << name << '\n';
std::cout << "age: " << age << '\n';
std::cout << "height: " << height << '\n';
std::cout << "grade: " << grade << '\n';
std::cout << "member: " << is_member << '\n';
}— end example]
It printed:
name: Ada
age: 36
height: 1.72
grade: A
member: true— end example]
The samples are C++17 (Since When’s C++17 table), built with MSVC 19.44 and Clang 19.1 (MSVC STL) on 64-bit Windows and with GCC 16.2 and Clang 23.1 (libc++) on 64-bit Linux. All four printed the same here.
What are the basic data types in C++?
They are the types built into the language, which the standard calls fundamental types; the ones you will use most are bool, char, the whole-number types short, int, long and long long, and the floating-point types float and double for numbers with a decimal point. The sizes and ranges below are what the four compilers printed on 64-bit desktops, not what the standard promises:
| Type | Holds | Bytes here | Range or precision |
|---|---|---|---|
bool |
true or false | 1 | false or true |
char |
one character | 1 | -128 to 127 |
short |
a small whole number | 2 | -32,768 to 32,767 |
int |
a whole number | 4 | about -2.1 billion to 2.1 billion |
long |
a whole number | 4 on Windows, 8 on Linux | as int on Windows, as long long on Linux |
long long |
a large whole number | 8 | about -9.2 quintillion to 9.2 quintillion |
float |
a number with a decimal point | 4 | 6 significant digits |
double |
the same, more precisely | 8 | 15 significant digits |

The standard fixes only minimums: int is at least 16 bits, long at least 32 and long long at least 64, and each is at least as large as the one before it ([basic.fundamental]). That leaves room for long to differ: 64-bit Windows keeps it at 4 bytes (Microsoft’s table of data type ranges), and 64-bit Linux makes it 8.
How do you check the size and range of a type on your machine?
sizeof(T) gives a type’s size in bytes, and std::numeric_limits, from <limits>, gives its range: max() is the largest value and, for a whole-number type, min() the smallest.
std::cout << "int: " << sizeof(int) << '\n';
std::cout << "long: " << sizeof(long) << '\n';
std::cout << "long long: " << sizeof(long long) << '\n';— end example]
int printed 4 and long long 8 on all four; long printed 4 on both Windows builds and 8 on both Linux builds.
std::cout << "int min: "
<< std::numeric_limits<int>::min() << '\n';
std::cout << "int max: "
<< std::numeric_limits<int>::max() << '\n';— end example]
All four printed -2147483648 and 2147483647. For float and double, min() is the smallest positive value held at full precision, not the most negative one; lowest() gives that. Their digits10 printed 6 for float and 15 for double: a float carries 6 significant decimal digits through without change and a double 15, the precision in the table.
Signed or unsigned, and what happens on overflow?
An unsigned type, such as unsigned int, holds no negative numbers and wraps around: one past its largest value is 0, and one below 0 is its largest value.
unsigned int u = 0;
std::cout << u - 1 << '\n'; // below zero: wraps to the top
unsigned int top = std::numeric_limits<unsigned int>::max();
std::cout << top + 1 << '\n'; // past the top: wraps to zero
unsigned int v = -5; // not an error: -5 wraps too
std::cout << v << '\n';— end example]
All four printed 4294967295, 0 and 4294967291, and only MSVC warned about the -5 (C4245 at /W4; Clang and GCC said nothing at -Wall -Wextra). The wrap is the standard’s rule: unsigned arithmetic, and converting a value such as -5 to an unsigned type, is done modulo 2 to the power N, where N is the type’s number of bits.
A signed type such as int has no such rule. A result past its largest value is undefined behavior ([expr.pre]): the standard places no requirement on what the program does next. Never rely on it; pick a type wide enough, such as long long for values past about 2.1 billion.
When does the exact size matter? (int32_t and friends)
It matters when the bytes leave your program, in a file format or a network message. Then use the fixed-width types from <cstdint>, which carry their width in the name; everywhere else, int is the default.
std::cout << sizeof(std::int32_t) << '\n'; // exactly 32 bits
std::cout << sizeof(std::int64_t) << '\n'; // exactly 64 bits
std::cout << sizeof(std::uint8_t) << '\n'; // exactly 8 bits
std::uint8_t age = 65;
std::cout << age << '\n'; // printed as a char
std::cout << static_cast<int>(age) << '\n'; // printed as a number— end example]
All four printed 4, 8 and 1, then A and 65: on these compilers std::uint8_t is another name for unsigned char, which std::cout prints as a character, so cast it to int to see the number. The u stands for unsigned.
What type does auto pick, and what do suffixes like 5u mean?
auto gives a variable the type of the value it starts with, and every literal, a value written in the code such as 5 or 'a', has a type: 5 is an int, 5.0 a double, and a suffix changes it.
auto n = 5; // int
auto x = 5.0; // double
auto f = 5.0f; // f: float
auto u = 5u; // u: unsigned int
auto big = 5LL; // LL: long long
auto c = 'a'; // char
auto s = "text"; // const char*, not std::string— end example]
Checked with std::is_same_v, every comment held on all four. The last line is the surprise: from a quoted literal auto makes a const char*, a pointer to characters, and s tested false as a std::string. Write the type when you want a string, as std:: does in the first program.
Why does int n{3.7} not compile?
Braces refuse a narrowing conversion, one that can lose data, whether or not this value would; double to int is one, and here the .7 would go:
int n{3.7}; // error: braces refuse to drop the .7— end example]
All four rejected it. Clang said:
error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]— end example]
With =, int n = 3.7; compiles and stores 3 on all four; MSVC and Clang warn, and GCC said nothing at -Wall -Wextra. Initialize with braces, and the lost data becomes an error instead of a 3 you may not notice.
Which C++ data type should you use?
Pick by what the value is. std::size_t is the unsigned type of the value sizeof gives, declared in <cstddef>. The rest of the basics are in the Language section.
| The value | Use |
|---|---|
| A whole number: a count, an age | int |
| A whole number past about 2.1 billion | long long |
| A number with a decimal point | double |
| One character | char |
| True or false | bool |
| Text | std::string |
| A size, or an index into a container | std::size_t |
| An exact width, for a file or the network | std::int32_t and the other <cstdint> types |
| One of a fixed list of names | an enum |
Questions
What is the size of int in C++?
The standard requires an int of at least 16 bits. On MSVC and Clang on 64-bit Windows and on GCC and Clang on 64-bit Linux it is 4 bytes (32 bits), with a range of -2,147,483,648 to 2,147,483,647. sizeof(int) prints the size on your own compiler.
What is the difference between float and double?
Size and precision. On MSVC, Clang and GCC on 64-bit desktops a float is 4 bytes and carries 6 significant decimal digits through without change, and a double is 8 bytes and carries 15 (std::numeric_limits digits10). Use double unless memory matters; a literal such as 5.0 is already a double.
Is string a data type in C++?
Not a built-in one. std::string is a class from the standard library, in the header <string>. The built-in char holds one character, and a quoted literal such as "Ada" is an array of chars; use std::string for words and sentences.
What is the difference between primitive and user-defined data types?
Primitive types, which the standard calls fundamental types, are built into the language: int, double, char, bool. User-defined types are the ones you or a library write with struct, class or enum; std::string is one, written by the standard library. Arrays, pointers and references, built from other types, are often called derived types.
What is the largest integer type in C++?
The largest standard integer types are long long and unsigned long long, which the standard requires to be at least 64 bits. On MSVC, Clang and GCC on 64-bit Windows and Linux, long long is 8 bytes and holds up to 9,223,372,036,854,775,807.
Is char signed or unsigned in C++?
The standard leaves it to the implementation: plain char has the range of either signed char or unsigned char, and the three are distinct types. On MSVC, Clang and GCC on x86-64 Windows and Linux, char was signed, -128 to 127. When the sign matters, write signed char or unsigned char.
Sources
- Fundamental typescppreference.com
- std::numeric_limitscppreference.com
- Fixed width integer typescppreference.com
- std::size_tcppreference.com
- Data type rangesMicrosoft Learn
- [basic.fundamental] Fundamental typesC++ standard working draft
- [expr.pre] Expressions: preambleC++ standard working draft