π 2015-Oct-12 ⬩ βοΈ Ashwin Nanjappa ⬩ π·οΈ cstdint, integer ⬩ π Archive
Traditional programmers are familiar with int
, long
and such integer types. These are known to have different sizes on different systems.
However, a lot of code requires integer types to be exactly a certain size or of at least a certain size. In such situations, it is a good idea to use the fixed width integer types provided by C++ through the header file cstdlib
.
C++ provides three types of fixed width integer types:
Integer of precisely the size you specify (Ex: int32_t
)
Smallest integer whose size is at least the size you specify (Ex: int_least32_t
)
Fastest integer whose size is at least the size you specify (Ex: int_fast32_t
)
List of the signed and unsigned integer types is:
int8_t
int16_t
int32_t
int64_t
uint8_t
uint16_t
uint32_t
uint64_t
int_least8_t
int_least16_t
int_least32_t
int_least64_t
uint_least8_t
uint_least16_t
uint_least32_t
uint_least64_t
int_fast8_t
int_fast16_t
int_fast32_t
int_fast64_t
uint_fast8_t
uint_fast16_t
uint_fast32_t
uint_fast64_t
When we specify that we want an integer to have exactly 32 bits, say int32_t
, that may not be supported on certain exotic systems. Assume a computer which supports only 34-bit and 68-bit integers. That system cannot provide a 32 bit integer. Code which uses int32_t
will not compile. This is good because the programmer who used int32_t
might have been assuming the type to have exactly 32 bits, for example, if he is looping over the 32 bits to compute something. Such code should fail, else it would be a bug.
Now the use of a precise width type, like int32_t
, provides the reason for the other two types of integers: smallest and fastest.
The smallest integer type, say int_least32_t
, should be used when our code requires to store values that need at least 32 bits, but our first priority is space and not speed of computation. For example, assume that the exotic system described above does 68-bit integer addition faster than 34-bit addition. In such a case, when we use int_least32_t
, we are asking it use the 34-bit type, foregoing speed for space.
The fastest integer type, say int_fast32_t
, should be used when our code requires to store values that need at least 32 bits, but our first priority is speed and not space. For example, in the exotic system described above when we use int_fast32_t
, that systemβs compiler will use the 68-bit type, providing the fastest integer addition, but by increasing space occupied by our program.
I now come back from a world of exotic computers to the common 64-bit x86_64 Intel processor system Iβm using. On GCC C++ compiler in Linux, I found that the smallest types (like int_least32_t
) were of the same size as the precise type (like int32_t
). No surprises there cause x86_64 has integers of size 8, 16, 32 and 64.
You will get a surprise if you use the fast types though! Except for the 8-bit fast types, the rest are all mapped to 64-bit signed and unsigned integers for speed. So, a int_fast16_t
is mapped to a 64-bit signed integer.
You can print out the sizes of all the fixed width integer types, by compiling and running a simple program, I have shared here:
#include <cstdint>
#include <iostream>
int main()
{std::cout << "Precise" << std::endl;
std::cout << sizeof(int8_t ) << std::endl;
std::cout << sizeof(int16_t ) << std::endl;
std::cout << sizeof(int32_t ) << std::endl;
std::cout << sizeof(int64_t ) << std::endl;
std::cout << sizeof(uint8_t ) << std::endl;
std::cout << sizeof(uint16_t) << std::endl;
std::cout << sizeof(uint32_t) << std::endl;
std::cout << sizeof(uint64_t) << std::endl;
std::cout << "Least" << std::endl;
std::cout << sizeof(int_least8_t ) << std::endl;
std::cout << sizeof(int_least16_t ) << std::endl;
std::cout << sizeof(int_least32_t ) << std::endl;
std::cout << sizeof(int_least64_t ) << std::endl;
std::cout << sizeof(uint_least8_t ) << std::endl;
std::cout << sizeof(uint_least16_t) << std::endl;
std::cout << sizeof(uint_least32_t) << std::endl;
std::cout << sizeof(uint_least64_t) << std::endl;
std::cout << "Fast" << std::endl;
std::cout << sizeof(int_fast8_t ) << std::endl;
std::cout << sizeof(int_fast16_t ) << std::endl;
std::cout << sizeof(int_fast32_t ) << std::endl;
std::cout << sizeof(int_fast64_t ) << std::endl;
std::cout << sizeof(uint_fast8_t ) << std::endl;
std::cout << sizeof(uint_fast16_t) << std::endl;
std::cout << sizeof(uint_fast32_t) << std::endl;
std::cout << sizeof(uint_fast64_t) << std::endl;
return 0;
}
Another method is to look at the source code. On my x86_64 Linux with GCC 5, the cstdint
trail leads to /usr/include/stdint.h
, where I find these definitions for the fast signed types:
/* Fast types. */
/* Signed. */
typedef signed char int_fast8_t;
#if __WORDSIZE == 64
typedef long int int_fast16_t;
typedef long int int_fast32_t;
typedef long int int_fast64_t;
#else
typedef int int_fast16_t;
typedef int int_fast32_t;
__extension__
typedef long long int int_fast64_t;
#endif
Tried with: GCC 5.1, Ubuntu 14.04 and x86_64 Intel CPU