Skip to content
  • Fundamental Types & Variables · C++

Fundamental Types & Variables

LearnViaNotes @learnvianotes· 4 min read

Every variable has a fixed type chosen at compile time. The type decides its size, its range and which operations are legal.

Built-in types

TypeTypical size (64-bit)Notes
bool1 bytetrue / false
char1 byteA character and a small integer; signedness is platform-defined
short2 bytesAt least 16 bits
int4 bytesAt least 16 bits — in practice 32
long8 bytes (Linux/macOS), 4 (Windows)At least 32 bits
long long8 bytesAt least 64 bits — use for big sums
float4 bytes~7 significant digits
double8 bytes~15–16 significant digits — the default for decimals
long double8–16 bytesExtended precision where supported
std::size_t8 bytesUnsigned; the type of sizeof and container sizes
C++
#include <climits>
#include <cstdint>
#include <iostream>
#include <limits>

int main() {
    std::cout << sizeof(int) << ' ' << sizeof(long long) << ' ' << sizeof(double) << '\n';
    std::cout << INT_MAX << ' ' << std::numeric_limits<int>::min() << '\n';
    std::cout << std::numeric_limits<long long>::max() << '\n';
    std::int32_t a = 1;          // exact-width types from <cstdint>
    std::uint64_t b = 1;
    std::cout << sizeof(a) << ' ' << sizeof(b) << '\n';
}
Output
4 8 8
2147483647 -2147483648
9223372036854775807
4 8

Ways to initialise

C++
#include <iostream>
int main() {
    int a = 5;        // copy initialisation
    int b(5);         // direct initialisation
    int c{5};         // brace (uniform) initialisation — C++11
    int d{};          // value-initialised → 0
    int e = {5};      // copy-list initialisation
    std::cout << a << b << c << d << e << '\n';
}
Output
55505

Brace initialisation refuses narrowing conversions — a lossy conversion becomes a compile error instead of a silent bug:

C++
int main() {
    double price = 9.99;
    int cents{price};     // error: narrowing conversion from double to int
    return cents;
}
Compiler error
error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]

Integer overflow & unsigned wrap-around

C++
#include <climits>
#include <iostream>
int main() {
    unsigned int u = 0;
    u = u - 1;                        // unsigned arithmetic wraps modulo 2^32
    std::cout << u << '\n';
    long long big = 1LL * INT_MAX * 2; // widen *before* multiplying
    std::cout << big << '\n';
    int s = -1;
    unsigned int one = 1;
    std::cout << (s < static_cast<int>(one)) << '\n';   // compare as signed
}
Output
4294967295
4294967294
1
C++ — signed overflow (UBSan aborts)
#include <climits>
#include <iostream>
int main() {
    int x = INT_MAX;
    x = x + 1;                // signed overflow: undefined behaviour
    std::cout << x << '\n';
}
UBSan
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'

Literals

LiteralType / meaning
42, 42u, 42L, 42LL, 42ULLint, unsigned, long, long long, unsigned long long
0x2A, 052, 0b101010Hex, octal, binary (C++14) — all 42
1'000'000Digit separators (C++14)
3.14, 3.14f, 1e9double, float, double
'a', "abc"char, const char[4] (array incl. '\0')
"abc"s, "abc"svstd::string, std::string_view (with using namespace std::literals)
nullptrThe null pointer literal (type std::nullptr_t)

Floating point is approximate

C++
#include <cmath>
#include <iostream>
int main() {
    double a = 0.1 + 0.2;
    std::cout << (a == 0.3) << '\n';                   // 0: not exactly equal
    std::cout << (std::fabs(a - 0.3) < 1e-9) << '\n';  // 1: compare with a tolerance
    std::cout << 7 / 2 << ' ' << 7 / 2.0 << '\n';      // integer vs floating division
}
Output
0
1
3 3.5

What is the difference between int x; and int x{}; inside a function?

Why prefer brace initialisation?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report