Fixed width integer types (int8) in C++

Binary Tree Problems books

Get FREE domain for 1st year and build your brand new site

If I ask you, "What is the size of an integer in C++?, what would be your answer?

  • 4 bytes?
  • 2 bytes?
  • 8 bytes?
    Well, here's the thing, it may be a slight oversimplification to keep it this way but C++ doesn't have a fixed size for integers.
    What C++ does have is a lower limit for integer size.
    C++ guarantees that signed short, unsigned short, signed int, and unsigned int are at least 16 bits or 2 bytes.

But, why isn't the size fixed?

Well, the reason goes back to 1969-1973 when C was being develloped at Bell Laboratories. C opted to intentionally leave the size of an integer open so that the compiler implementors could pick a size for int that performs best on the target computer architecture.

What are fixed-width integers?

C99 has defined a set of fixed-width integers that are guaranteed to have the same size on any architecture. These can be found in stdint.h header.

Width Signed Type Unsigned Type
8 bits int8_t uint8_t
16 bits int16_t uint16_t
32 bits int32_t uint32_t
64 bits int64_t uint64_t

C++ officially adopted these fixed-width integers as part of C++11. They can be accessed by including the cstdint header, where they are defined inside the std namespace.

fixed-width-int

Code Example

If you're a beginner the code below may seem a bit daunting.
Here are some points that will help you understand the code below:

  • uint64_t and int64_t are optional integer types of exactly 64 bits. In the code below, we use int64_t.
  • uint64_t is unsigned, and has the range zero to UINT64_MAX, which is [0, +18446744073709551615].
  • The following macros can be used in the fmt argument of printf to print arguments of types uint64_t and int64_t:
  • PRIu64
  • PRIo64
  • PRIx64
  • PRIX64
  • PRId64
  • PRIi64
    (What are macros and how do they work is beyond the scope of this article.)
  • For easier understanding, think of PRId64 as a necessary keyword to print an int64_t integer with the base 10. In other words, PRId64 is the decimal output conversion specifier for int64_t.

Now, you can understand the code below.

#include <cstdio>
#include <cinttypes>
 
int main()
{
    std::printf("%zu\n", sizeof(std::int64_t));
    std::printf("%s\n", PRId64);
    std::printf("%+" PRId64 "\n", INT64_MIN);
    std::printf("%+" PRId64 "\n", INT64_MAX);
 
    std::int64_t n = 7;
    std::printf("%+" PRId64 "\n", n);
}

Possible Output

8
lld
-9223372036854775808
+9223372036854775807
+7

Try printing INT64_MIN and INT64_MAX without PRId64 and you'll understand the need for the macro.

What if you want to uint64_t in the above code? Will PRId64 still work? Nope. The decimal output conversion specifier for uint64_t is PRIu64. Quite cumbersome to remember all these, isn't it?

So, why don't we always use fixed-width integers?

If the target is to write portable code, it's a good point to remember that the fixed-width types are all optional.

Although the use of fixed-size integer types will mean that the sizes of one's variables won't change if compilers use different sizes for int, long, and so on, it doesn't guarantee that the code will behave in exactly the same manner on machines with various integer sizes, even when the sizes are defined.

For example, given declaration uint32_t i;, the behavior of expression (i-1) > 5 when i is zero will vary depending upon whether a uint32_t is smaller than int. On systems where, int is 64 bits (and uint32_t is something like long short), the variable i would get promoted to int; the subtraction and comparison would be performed as signed (-1 is less than 5). On systems where int is 32 bits, the subtraction and comparison would be performed as unsigned int (the subtraction would yield a really big number, which is greater than five).

The code should conclusively reveal to the casual reader (and the programmer) what is important. Is it just some integer or unsigned integer or even signed integer? The same goes for size. Is it essential to the algorithm that some variable is by default 32 bit? Or is it just unnecessary micromanagement and a failed attempt to optimize? In practice, most people never need to write code with such a high degree of portability.

With this, you know how to reduce the size of standard data types like INT and use it accordingly.

With this OpenGenus article, you must have the complete idea of Fixed width integer types (int8) in C++.