About sizes

Author: Chloé Lourseyre

If I’d come up with a pop quiz about sizes in C++, most C++ developers would fail it (I know I would), because sizes in C++ are complicated.

The size of every fundamental type is not fixed, they are always implementation-defined.

Sill, the standard defines constraints on these sizes. These constraints take the form of one of these:

  • A comparison of the types’ sizeof.
  • The type’s minimum number of bits.

What is sizeof()?

One of the most widespread (and harmless) misconceptions about type sizes is that a byte holds 8 bits.

Although this is mostly true in practice, this is technically false.

A byte is actually defined as the size of a char. Though a char must have at least 8 bits, it can hold more. sizeof(N) returns the number of bytes of the type N, and every type size is expressed in terms of a char length. Thus, a 4-byte int is at least 32-bit, but you may not assume more from it (it could be 128-bit if a char is 32-bit).

The actual size of a byte is recorded in CHAR_BIT

Summary of sizes in C++

Here are all the definitions and restrictions of fundamental types’ sizes in C++:

  • 1 ≡ sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long) ≤ sizeof(long long)
  • 1 ≤ sizeof(bool) ≤ sizeof(long)
  • sizeof(char) ≤ sizeof(wchar_t) ≤ sizeof(long)
  • sizeof(float) ≤ sizeof(double) ≤ sizeof(long double)
  • sizeof(N) ≡ sizeof(unsigned N) ≡ sizeof(signed N)
  • A char has at least 8 bits
  • A short has at least 16 bits
  • A long has at least 32 bits

… and nothing more.

Fun fact: according to this definition, it is technically possible that all fundamentals have 32 bits.

Two words of wisdom

Since the sizes of the fundamental types entirely depend on the architecture, it may sometimes be hard to write consistent code.

#include <limits>

limits of the standard library contains the upper and lower limits of every fundamental type, and allows you to know if a given type is signed or not.

Example:

#include <limits>
#include <iostream>

int main()
{
    std::cout << "largest double == " << std::numeric_limits<double>::max() << std::endl;
    std::cout << "char is signed == " << std::numeric_limits<char>::is_signed << std::endl;
}

More at std::numeric_limits – cppreference.com.

Reminder: signed integer overflow is undefined behavior. Using limits helps you in preventing that from happening.

#include <cstdint>

Sometimes you may want to deal with fixed-sized types (in terms of bit) and not rely on the implementation specifics. For instance, if you implement serialization, work on very limited memory space, or develop cross-platform software, you may want to explicitly provide the bit-size of the type you’re using.

You can do so with the library cstdint which contains fixed-size types.

Here are a few of them:

int8_t
int16_t
int32_t
int64_t
Signed integer type with width of exactly 8, 16, 32 and 64 bits respectively
with no padding bits and using 2’s complement for negative values
(provided only if the implementation directly supports the type)
int_least8_t
int_least16_t
int_least32_t
int_least64_t
Smallest signed integer type with width of at least 8, 16, 32 and 64 bits respectively
intmax_tMaximum-width signed integer type
uint8_t
uint16_t
uint32_t
uint64_t
Unsigned integer type with width of exactly 8, 16, 32 and 64 bits respectively
(provided only if the implementation directly supports the type)
uint_least8_t
uint_least16_t
uint_least32_t
uint_least64_t
smallest unsigned integer type with width of at least 8, 16, 32 and 64 bits respectively
uintmax_tmaximum-width unsigned integer type

More at Fixed width integer types (since C++11) – cppreference.com.

Wrapping up

If you want to read more about type size, refer to section §6.2.8 of The C++ Langage (Bjarne Stroustrup). More broadly, you can read about types and declarations in the whole section §6 of the book.

You can also refer to Fundamental types – cppreference.com for online documentation

Thanks for reading and see you next week!

Author: Chloé Lourseyre

6 thoughts on “About sizes”

Leave a Reply