Integer Types

To use standardized integer types, always include the <cstdint> and <cstddef> headers:


#include <cstdint>
#include <cstddef> //::std::size_t and ::std::ptrdiff_t are in cstddef

For an N‑bit integer: Unsigned range = 0 to 2^N − 1 Signed range = −2^(N−1) to 2^(N−1) − 1

Formula to compute bytes: bytes = N / 8.

Bits Bytes Unsigned range Signed range
8 1 0 to 255 -128 to 127
16 2 0 to 65535 -32768 to 32767
32 4 0 to 4294967295 -2147483648 to 2147483647
64 8 0 to 18446744073709551615 -9223372036854775808 to 9223372036854775807
128 16 0 to 340282366920938463463374607431768211455 -170141183460469231731687303715884105728 to 170141183460469231731687303715884105727

Least, Fast, and Exact Types

C++ defines three families of integer types:

Why exact-width types may not exist

Exact-width types are optional. They may be missing if:

On the overwhelming majority of platforms this is not a problem, but if you want maximum portability you should use ::std::int_leastXX_t and ::std::uint_leastXX_t. If ::std::uintXX_t does exist, it is guaranteed to be identical to ::std::uint_leastXX_t.

Examples


#include <cstdint>
#include <fast_io.h>

int main() {
    using namespace ::fast_io::iomnp;

    ::std::int_least32_t a = -123;   // guaranteed at least 32 bits
    ::std::uint_least64_t b = 1000;  // guaranteed at least 64 bits
    ::std::int_fast16_t c = 42;      // fastest type with ≥16 bits
    ::std::uint8_t d = 255;          // exact 8-bit type (if available)

    println("a = ", a, "\n"          // prints -123
            "b = ", b, "\n"          // prints 1000
            "c = ", c, "\n"          // prints 42
            "d = ", d);              // prints 255
}

Best Practices

Floating Point Types

To use standardized floating point types, always include the <stdfloat> header:


#include <stdfloat>

Floating point numbers represent real values with decimals. They can cover very large and very small magnitudes, but they are approximate and can introduce rounding errors. Unlike integers, floating point values are not exact.

These types are defined according to the IEC 559 standard (also known as IEEE 754), which specifies how floating point numbers are represented and how operations on them behave.

Type Bits Bytes Approx. Range Precision Notes
::std::bfloat16_t 16 2 ~10^±38 ~3 decimal digits Mainly used in AI/ML workloads for reduced precision but faster computation
::std::float16_t 16 2 ~10^±5 ~3–4 decimal digits Half precision, common in graphics and embedded systems
::std::float32_t 32 4 ~10^±38 ~7 decimal digits Single precision, equivalent to float
::std::float64_t 64 8 ~10^±308 ~15–16 decimal digits Double precision, preferred over double for clarity
::std::float128_t 128 16 ~10^±4932 ~33–34 decimal digits Quadruple precision, used in high‑precision scientific computing

Examples


// Define a reduced-precision floating point (AI/ML)
::std::bfloat16_t bf = 1.5f;

// Define a 16-bit floating point
::std::float16_t f16 = 3.14f;

// Define a 32-bit floating point
::std::float32_t f32 = 2.71828f;

// Define a 64-bit floating point
::std::float64_t f64 = 3.141592653589793;

// Define a 128-bit floating point
::std::float128_t f128 = 1.234567890123456789012345678901234Q;

Why we prefer integers first

Integers are exact: they represent whole numbers without rounding. Floating point types are powerful for scientific and mathematical work, but they can lose precision. For counting, indexing, and sizes, integers are safer and more predictable.

Another reason is portability: not all platforms support floating point types. Some embedded systems or unusual environments may lack hardware floating point units, or emulate them very slowly. Even when floating point is supported, you may face restrictions — for example, the Linux kernel does not allow floating point operations in kernel space. This means that relying on floating point types can reduce portability or cause problems in low-level programming contexts.

Therefore, while floating point types are essential for scientific calculations, graphics, and machine learning, integers remain the most portable and reliable choice for general programming tasks.

Traditional Integer Types

Before standardized fixed-width types (::std::int_leastXX_t, ::std::uint_leastXX_t), C++ provided traditional integer types: char, short, int, long, long long, and their unsigned versions.

What the standard guarantees

That’s all the standard guarantees. It does not fix exact sizes. For example, int could be 16 bits, 32 bits, 64 bits, or even something absurd like 100000 bits — and it would still be valid according to the standard. This means we cannot rely on int having a predictable size across platforms.

Examples


// Traditional integer types

// char is exactly 1 byte. Here we assign it an integer in [0,127],
// which corresponds to ASCII codes (e.g. 97 = 'a', but we will
// explain character literals later).
char c = 97;                 // implementation-defined signedness

short s = 123;               // minimum 16 bits, no larger than int
int i = 456;                 // minimum 16 bits, no larger than long
long l = 789;                // minimum 32 bits, no larger than long long
long long ll = 123456789LL;  // minimum 64 bits

// Unsigned versions
unsigned short us = 123;
unsigned int ui = 1000;
unsigned long ul = 50000;
unsigned long long ull = 100000000ULL;

Why we prefer standardized types

Because the sizes of int, long, and others are not guaranteed beyond these minimums and relative constraints, portable code should use standardized types like ::std::int_least32_t or ::std::uint_least64_t. These give clear, predictable guarantees across platforms.

Traditional Floating Point Types

In addition to integers, C++ provides traditional floating point types: float, double, and long double.

What the standard guarantees

The standard does not fix exact sizes or ranges for these types. Instead, it only guarantees minimum precision and ordering: float ≤ double ≤ long double in terms of precision and range. On most modern platforms:

Because the standard only specifies minimum guarantees, you cannot assume exact sizes or formats. For example, long double might be identical to double on some systems, while on others it may provide extended precision.

Examples


// Traditional floating point types

float f = 3.14f;             // at least 6 decimal digits precision
double d = 2.718281828;      // at least as precise as float, usually ~15 digits
long double ld = 1.618033988749894L; // at least as precise as double, may be more

Why standardized types are preferred

Just as with integers, the traditional floating point types have only minimum guarantees. For predictable behavior across platforms, modern C++ provides standardized types such as ::std::float32_t, ::std::float64_t, and ::std::float128_t (defined by the IEC 559 / IEEE 754 standard). These give clear, fixed sizes and precision guarantees, unlike the traditional types.

Boolean Type

C++ provides a dedicated logical type: bool. Unlike integers or floating point types, bool is designed specifically to represent truth values.

What the standard guarantees

Examples


// Boolean type

bool flag1 = true;    // explicitly true
bool flag2 = false;   // explicitly false

// Conversion from integers
bool b1 = 0;          // becomes false
bool b2 = 1;          // becomes true
bool b3 = 42;         // any non-zero becomes true
bool b4 = -42;        // any non-zero (including negative) becomes true

Printing with fast_io


#include <fast_io.h>
#include <cstddef>
#include <stdfloat>

int main()
{
    using namespace ::fast_io::iomnp;

    bool flag = true;

    // Default printing: outputs 0 or 1
    // With boolalpha: outputs textual true/false
    println(flag,        // prints "1"
            " ", 
            boolalpha(flag)); // prints "true"

    // boolalpha also applies to integers and floating point types.
    // Any non-zero value will print as "true", zero prints as "false".
    ::std::size_t i = 42;
    ::std::float64_t d = 0.0;

    println(boolalpha(i),   // prints "true"
            "\n",
            boolalpha(d));  // prints "false"
}

Usage

bool is primarily used in conditions, comparisons, and control flow. With fast_io, you can choose whether to print it as 0/1 or as true/false using boolalpha. The same manipulator can be applied to integers and floating point values to interpret them as logical truth values.

Character Data Types

C++ provides several character types to represent text in different encodings. Although char is the most common, modern C++ introduces char8_t, char16_t, and char32_t for Unicode support, plus wchar_t for wide characters.

Type Size Encoding Example
char 1 byte Implementation-defined (usually ASCII or UTF-8) char c = 'A';
char8_t 1 byte UTF-8 code unit char8_t u8c = u8'A';
char16_t 2 bytes UTF-16 code unit char16_t u16c = u'A';
char32_t 4 bytes UTF-32 code unit char32_t u32c = U'A';
wchar_t Implementation-defined (2 or 4 bytes) Wide character (platform-dependent) wchar_t wc = L'A';

#include <fast_io.h>

int main()
{
    using namespace ::fast_io::iomnp;

    char c = 'A';
    char8_t u8c = u8'A';
    char16_t u16c = u'A';
    char32_t u32c = U'A';
    wchar_t wc = L'A';

    // Print numeric values
    println(c);    // prints 65
    println(u8c);  // prints 65
    println(u16c); // prints 65
    println(u32c); // prints 65
    println(wc);   // prints 65

    // Print as characters
    println(chvw(c));    // prints A
    println(chvw(u8c));  // prints A
    println(chvw(u16c)); // prints A
    println(chvw(u32c)); // prints A
    println(chvw(wc));   // prints A
}

Important: All of these char types are still integer types under the hood. The literal 'A' is stored as the numeric value 65 (its ASCII/Unicode code point). That’s why calling println(c) prints 65 — you are seeing the integer value. To display the character itself, you use manipulators like chvw(), which interpret the integer as a character for output.

Note: When printing UTF string literals (u8"...", u"...", U"..."), you must use code_cvt(...) unless you specify a device that matches the character type. By default, print/println/scan are tied to char and FILE*. We will explain devices and encoding in detail in the future I/O chapter.

Appendix: ASCII Table (0–127)