Most modern computer architecture is 1 byte = 8 bits, but that can't be assumed to always be true. C/C++ has a way to check for the number of bits in a byte. <climits> has the CHAR_BIT macro constant for the number of bits in a byte.
https://en.cppreference.com/w/cpp/types/climits
So we can now determine the number of bytes (and bits) consumed with each type using the
sizeof operator.
sizeof returns the number of bytes for a type:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
#include <iostream>
#include <climits>
int main()
{
std::cout << "CHAR_BIT (bits in a byte): " << CHAR_BIT << "\n\n";
std::cout << "Computing the size in bytes of some C and C++ built-in variable types\n\n";
std::cout << "Size of bool: " << sizeof(bool) << '\n';
std::cout << "Size of char: " << sizeof(char) << '\n';
std::cout << "Size of wchar_t: " << sizeof(wchar_t) << '\n';
std::cout << "Size of unsigned short int: " << sizeof(unsigned short) << '\n';
std::cout << "Size of short: " << sizeof(short) << '\n';
std::cout << "Size of unsigned long int: " << sizeof(unsigned long) << '\n';
std::cout << "Size of long: " << sizeof(long) << '\n';
std::cout << "Size of int: " << sizeof(int) << '\n';
std::cout << "Size of unsigned int: " << sizeof(unsigned int) << '\n';
std::cout << "Size of float: " << sizeof(float) << '\n';
std::cout << "Size of double: " << sizeof(double) << "\n\n";
std::cout << "The output can change with compiler, processor type and OS\n\n";
std::cout << "C++11 added several new fundamental variable types.\n";
std::cout << "The values can change whether compiled as 32 or 64 bit.\n\n";
std::cout << "Size of char16_t: " << sizeof(char16_t) << '\n';
std::cout << "Size of char32_t: " << sizeof(char32_t) << '\n';
std::cout << "Size of unsigned long long: " << sizeof(unsigned long long) << '\n';
std::cout << "Size of long long: " << sizeof(long long) << '\n';
std::cout << "Size of long double: " << sizeof(long double) << '\n';
std::cout << "Size of nullptr: " << sizeof(nullptr) << '\n';
}
| |
(Compiled as 32-bit)
CHAR_BIT (bits in a byte): 8
Computing the size in bytes of some C and C++ built-in variable types
Size of bool: 1
Size of char: 1
Size of wchar_t: 2
Size of unsigned short int: 2
Size of short: 2
Size of unsigned long int: 4
Size of long: 4
Size of int: 4
Size of unsigned int: 4
Size of float: 4
Size of double: 8
The output can change with compiler, processor type and OS
C++11 added several new fundamental variable types.
The values can change whether compiled as 32 or 64 bit.
Size of char16_t: 2
Size of char32_t: 4
Size of unsigned long long: 8
Size of long long: 8
Size of long double: 8
Size of nullptr: 4 |
With Visual Studio the only value that changes between 32 and 64 bit is
nullptr. 64-bit
nullptr is 8 bytes.
TDM-GCC/MinGW has another type (in addition to
nullptr) that can vary in size,
long double. 32-bit is 12 bytes, 64-bit is 16 bytes.
To make matters worse with pointers the exact memory layout can vary between compilers and the bitness.
1 2 3 4 5 6 7 8 9 10
|
#include <iostream>
int main()
{
int x = 10;
int* xPtr = &x;
std::cout << sizeof(x) << ", " << x << ",\n" << &x << "\n\n";
std::cout << sizeof(xPtr) << ", " << xPtr << ",\n" << &xPtr << '\n';
}
| |
VS 32-bit
4, 10,
00AFF798
4, 00AFF798,
00AFF794 |
M'ok, the layout is 4 bytes apart, as expected. Memory is allocated from "the bottom up." VS 64-bit
4, 10,
0000001B40FAFAE8
8, 0000001B40FAFAE8,
0000001B40FAFAE0 |
8 byte difference. As expected. Now let's try MinGW-64 32-bit:
4, 10,
0x6dfeb8
4, 0x6dfeb8,
0x6dfebc |
4 byte diff, and the layout is reversed from how VS does its memory layout. MinGW-64 64-bit:
4, 10,
0x72fe14
8, 0x72fe14,
0x72fe18 |
Despite the memory locations being different the layout is still "kosher."
Now let's try TDM-GCC 9.2. 32-bit:
4, 10,
0x77febc
4, 0x77febc,
0x77feb8 |
4 bytes, TDM-GCC does "bottom up" memory layouts, similar to VS. Curiouser and curiouser. TDM-GCC 64-bit:
4, 10,
0x78fe1c
8, 0x78fe1c,
0x78fe10 |
Again, "bottom up" layout, but wait. The difference in 64-bit is 12(!) bytes. Yow!
So without doing any pointer memory tests making assumptions about the number of bits in a byte, the number of bytes, the bitness as compiled and their memory layout for pointers is gonna bite one in the butt. Big time.
Another possible thing to get one's arse chewed on, the pointer memory locations with MinGW/TDM-GCC are fixed at compile time, each time the app is run the pointers are at the same memory location. With VS the memory locations vary with each run.