Integer Limits and Types In C/C++
Unlike Java or C#, primitive data types in C++ can vary in size depending on the platform. For example, int is not guaranteed to be a 32-bit integer. The size of basic C++ types depends on
The Architecture (16 bits, 32 bits, 64 bits)
You can expect std::size_t to always represent the unsigned native integer size on current architecture. i.e. 16-bit, 32-bit or 64-bit. e.g
On a x64-bit machine, with x86_64 hardware-platform and processor,
sizeof(std::size_t) == sizeof(unsigned int) == 8
where as, on a 32-bit machine, with i386 hardware-platform and i686 processor,
sizeof(std::size_t) == sizeof(unsigned int) == 4
But as far as all the other built-in types go, it really depends on the compiler.
The Compiler
The C++ standard does not specify the size of integral types in bytes, but it specifies minimum ranges they must be able to hold. You can infer minimum size in bits from the required range and the value of CHAR_BIT
macro in <climits>, that defines the number of bits in a byte (in all but the most obscure platforms it’s 8).
An important point to note for char
is that its size is always 1 byte, or CHAR_BIT
bits (hence the name). char is always a byte , but it’s not always an octet. A byte is the smallest addressable unit of memory (in most definitions), an octet is 8-bit unit of memory. i.e sizeof(char) == 1
for all implementations, but CHAR_BIT
defines the size of a byte for a platform and it’s not always 8 bit. There are platforms with 16-bit and 32-bit bytes, hence char will take up more than 8 bits, but it is still a byte.
A C++ (or C) implementation can define the size of a type in bytes sizeof(type)
to any value, as long as
- the expression
sizeof(type) * CHAR_BIT
evaluates to the number of bits enough to contain required ranges, and - the ordering of type is still valid (e.g.
sizeof(int) <= sizeof(long)
).
The actual implementation-specific ranges can be found in <limits.h> header in C, or <climits> in C++ (or even better, templated std::numeric_limits in <limits> header). Minimum ranges required by the standard (page 22) can be found using this C++ snippet:
integral_type_sizes.cpp
#include <iostream>
#include <limits>
using namespace std;
int main()
{
cout << "Size of size_t = " << sizeof(std::size_t) << endl << endl;
cout << "Minimum value for bool: " << numeric_limits<bool>::min() << endl;
cout << "Maximum value for bool: " << numeric_limits<bool>::max() << endl;
cout << "bool is signed: " << numeric_limits<bool>::is_signed << endl;
cout << "Non-sign bits in bool: " << numeric_limits<bool>::digits << endl;
cout << "bool has infinity: " << numeric_limits<bool>::has_infinity << endl << endl;
cout << "Minimum value for char: " << numeric_limits<char>::min() << endl;
cout << "Maximum value for char: " << numeric_limits<char>::max() << endl;
cout << "char is signed: " << numeric_limits<char>::is_signed << endl;
cout << "Non-sign bits in char: " << numeric_limits<char>::digits << endl;
cout << "char has infinity: " << numeric_limits<char>::has_infinity << endl << endl;
cout << "Minimum value for signed char: " << numeric_limits<signed char>::min() << endl;
cout << "Maximum value for signed char: " << numeric_limits<signed char>::max() << endl;
cout << "signed char is signed: " << numeric_limits<signed char>::is_signed << endl;
cout << "Non-sign bits in signed char: " << numeric_limits<signed char>::digits << endl;
cout << "signed char has infinity: " << numeric_limits<signed char>::has_infinity << endl << endl;
cout << "Minimum value for unsigned char: " << numeric_limits<unsigned char>::min() << endl;
cout << "Maximum value for unsigned char: " << numeric_limits<unsigned char>::max() << endl;
cout << "unsigned char is signed: " << numeric_limits<unsigned char>::is_signed << endl;
cout << "Non-sign bits in unsigned char: " << numeric_limits<unsigned char>::digits << endl;
cout << "unsigned char has infinity: " << numeric_limits<unsigned char>::has_infinity << endl << endl;
cout << "Minimum value for wchar_t: " << numeric_limits<wchar_t>::min() << endl;
cout << "Maximum value for wchar_t: " << numeric_limits<wchar_t>::max() << endl;
cout << "wchar_t is signed: " << numeric_limits<wchar_t>::is_signed << endl;
cout << "Non-sign bits in wchar_t: " << numeric_limits<wchar_t>::digits << endl;
cout << "wchar_t has infinity: " << numeric_limits<wchar_t>::has_infinity << endl << endl;
cout << "Minimum value for short: " << numeric_limits<short>::min() << endl;
cout << "Maximum value for short: " << numeric_limits<short>::max() << endl;
cout << "short is signed: " << numeric_limits<short>::is_signed << endl;
cout << "Non-sign bits in short: " << numeric_limits<short>::digits << endl;
cout << "short has infinity: " << numeric_limits<short>::has_infinity << endl << endl;
cout << "Minimum value for unsigned short: " << numeric_limits<unsigned short>::min() << endl;
cout << "Maximum value for unsigned short: " << numeric_limits<unsigned short>::max() << endl;
cout << "unsigned short is signed: " << numeric_limits<unsigned short>::is_signed << endl;
cout << "Non-sign bits in unsigned short: " << numeric_limits<unsigned short>::digits << endl;
cout << "unsigned short has infinity: " << numeric_limits<unsigned short>::has_infinity << endl << endl;
cout << "Minimum value for int: " << numeric_limits<int>::min() << endl;
cout << "Maximum value for int: " << numeric_limits<int>::max() << endl;
cout << "int is signed: " << numeric_limits<int>::is_signed << endl;
cout << "Non-sign bits in int: " << numeric_limits<int>::digits << endl;
cout << "int has infinity: " << numeric_limits<int>::has_infinity << endl << endl;
cout << "Minimum value for unsigned int: " << numeric_limits<unsigned int>::min() << endl;
cout << "Maximum value for unsigned int: " << numeric_limits<unsigned int>::max() << endl;
cout << "unsigned int is signed: " << numeric_limits<unsigned int>::is_signed << endl;
cout << "Non-sign bits in unsigned int: " << numeric_limits<unsigned int>::digits << endl;
cout << "unsigned int has infinity: " << numeric_limits<unsigned int>::has_infinity << endl << endl;
cout << "Minimum value for long: " << numeric_limits<long>::min() << endl;
cout << "Maximum value for long: " << numeric_limits<long>::max() << endl;
cout << "long is signed: " << numeric_limits<long>::is_signed << endl;
cout << "Non-sign bits in long: " << numeric_limits<long>::digits << endl;
cout << "long has infinity: " << numeric_limits<long>::has_infinity << endl << endl;
cout << "Minimum value for unsigned long: " << numeric_limits<unsigned long>::min() << endl;
cout << "Maximum value for unsigned long: " << numeric_limits<unsigned long>::max() << endl;
cout << "unsigned long is signed: " << numeric_limits<unsigned long>::is_signed << endl;
cout << "Non-sign bits in unsigned long: " << numeric_limits<unsigned long>::digits << endl;
cout << "unsigned long has infinity: " << numeric_limits<unsigned long>::has_infinity << endl << endl;
cout << "Minimum value for long long: " << numeric_limits<long long>::min() << endl;
cout << "Maximum value for long long: " << numeric_limits<long long>::max() << endl;
cout << "long long is signed: " << numeric_limits<long long>::is_signed << endl;
cout << "Non-sign bits in long long: " << numeric_limits<long long>::digits << endl;
cout << "long long has infinity: " << numeric_limits<long long>::has_infinity << endl << endl;
cout << "Minimum value for unsigned long long: " << numeric_limits<unsigned long long>::min() << endl;
cout << "Maximum value for unsigned long long: " << numeric_limits<unsigned long long>::max() << endl;
cout << "unsigned long long is signed: " << numeric_limits<unsigned long long>::is_signed << endl;
cout << "Non-sign bits in unsigned long long: " << numeric_limits<unsigned long long>::digits << endl;
cout << "unsigned long long has infinity: " << numeric_limits<unsigned long long>::has_infinity << endl << endl;
cout << "Minimum value for float: " << numeric_limits<float>::min() << endl;
cout << "Maximum value for float: " << numeric_limits<float>::max() << endl;
cout << "float is signed: " << numeric_limits<float>::is_signed << endl;
cout << "Non-sign bits in float: " << numeric_limits<float>::digits << endl;
cout << "float has infinity: " << numeric_limits<float>::has_infinity << endl << endl;
cout << "Minimum value for double: " << numeric_limits<double>::min() << endl;
cout << "Maximum value for double: " << numeric_limits<double>::max() << endl;
cout << "double is signed: " << numeric_limits<double>::is_signed << endl;
cout << "Non-sign bits in double: " << numeric_limits<double>::digits << endl;
cout << "double has infinity: " << numeric_limits<double>::has_infinity << endl << endl;
cout << "Minimum value for long double: " << numeric_limits<long double>::min() << endl;
cout << "Maximum value for long double: " << numeric_limits<long double>::max() << endl;
cout << "long double is signed: " << numeric_limits<long double>::is_signed << endl;
cout << "Non-sign bits in long double: " << numeric_limits<long double>::digits << endl;
cout << "long double has infinity: " << numeric_limits<long double>::has_infinity << endl << endl;
return 0;
}
returns the following output:
Size of size_t = 8
Minimum value for bool: 0
Maximum value for bool: 1
bool is signed: 0
Non-sign bits in bool: 1
bool has infinity: 0
Minimum value for char: ?
Maximum value for char:
char is signed: 1
Non-sign bits in char: 7
char has infinity: 0
Minimum value for signed char: ?
Maximum value for signed char:
signed char is signed: 1
Non-sign bits in signed char: 7
signed char has infinity: 0
Minimum value for unsigned char:
Maximum value for unsigned char: ?
unsigned char is signed: 0
Non-sign bits in unsigned char: 8
unsigned char has infinity: 0
Minimum value for wchar_t: -2147483648
Maximum value for wchar_t: 2147483647
wchar_t is signed: 1
Non-sign bits in wchar_t: 31
wchar_t has infinity: 0
Minimum value for short: -32768
Maximum value for short: 32767
short is signed: 1
Non-sign bits in short: 15
short has infinity: 0
Minimum value for unsigned short: 0
Maximum value for unsigned short: 65535
unsigned short is signed: 0
Non-sign bits in unsigned short: 16
unsigned short has infinity: 0
Minimum value for int: -2147483648
Maximum value for int: 2147483647
int is signed: 1
Non-sign bits in int: 31
int has infinity: 0
Minimum value for unsigned int: 0
Maximum value for unsigned int: 4294967295
unsigned int is signed: 0
Non-sign bits in unsigned int: 32
unsigned int has infinity: 0
Minimum value for long: -9223372036854775808
Maximum value for long: 9223372036854775807
long is signed: 1
Non-sign bits in long: 63
long has infinity: 0
Minimum value for unsigned long: 0
Maximum value for unsigned long: 18446744073709551615
unsigned long is signed: 0
Non-sign bits in unsigned long: 64
unsigned long has infinity: 0
Minimum value for long long: -9223372036854775808
Maximum value for long long: 9223372036854775807
long long is signed: 1
Non-sign bits in long long: 63
long long has infinity: 0
Minimum value for unsigned long long: 0
Maximum value for unsigned long long: 18446744073709551615
unsigned long long is signed: 0
Non-sign bits in unsigned long long: 64
unsigned long long has infinity: 0
Minimum value for float: 1.17549e-38
Maximum value for float: 3.40282e+38
float is signed: 1
Non-sign bits in float: 24
float has infinity: 1
Minimum value for double: 2.22507e-308
Maximum value for double: 1.79769e+308
double is signed: 1
Non-sign bits in double: 53
double has infinity: 1
Minimum value for long double: 3.3621e-4932
Maximum value for long double: 1.18973e+4932
long double is signed: 1
Non-sign bits in long double: 64
long double has infinity: 1
Portability
If you are concerned with portability and want guaranteed size, or you want the name of the type reflects the size,
- You can use the header BOOST cstdint. It’s usually better than inventing your own wheel(which incurs the maintainence and testing), or
- You can use the header <cinttypes>, where the following macros are available:
int8_t, int16_t, int32_t, uint8_t, uint16_t, uint32_t
etc.
For more information on this, refer Wiki- Inttypes.h.
Enjoy Reading This Article?
Here are some more articles you might like to read next: