Show Lecture.FixedWidthIntegers as a slide show.
CS253 Fixed Width Integers
The Rules
Unlike languages such as Java, C++ integer sizes aren’t fixed:
This Computer
char c = -1;
cout << "char is " << (c<0 ? "signed\n" : "unsigned\n")
<< "char signed: " << boolalpha
<< numeric_limits<char>::is_signed << '\n'
<< "char: " << sizeof(char) << '\n'
<< "short: " << sizeof(short) << '\n'
<< "int: " << sizeof(int) << '\n'
<< "long: " << sizeof(long) << '\n'
<< "long long: " << sizeof(long long) << '\n';
char is signed
char signed: true
char: 1
short: 2
int: 4
long: 8
long long: 8
Rationale
The intention is that int is the natural size for integer values on
this computer. The C/C++ languages are quite concerned about
efficiency, and int operations must be quick. It would be silly to
have a 64-bit computer doing extra work to fake overflow in a 16-bit
int.
On 16-bit computers, int was 16 bits. int has been stuck at 32 bits
for too long, maybe due to bad code that assumes 32-bit ints.
Indeed, occasionally, I want an integer type that is exactly 32
bits. Perhaps I’m simulating hardware that has 32-bit registers.
Perhaps I want reproducible overflow characteristics for a random
number generator.
Poor Solution
- So, how do I reliably get a 32-bit integer?
- The old solution was to use conditional compilation:
#ifdef STUPID_16_BIT_COMPUTER
typedef long int32;
#elif MAC_COMPUTER
typedef int int32;
#elif HP_COMPUTER
typedef long long int32;
#else
#error Cannot figure out 32-bit int size.
#endif
Fragile!
Better Solution
Rather than guessing sizes, based on compiler version and machine
type, it would be great if we could convince the compiler implementors
(who actually know) to tell us how to get integers of various sizes.
That’s what the <cstdint> header file is for.
<cstdint> (alias <stdint.h> in C) provides aliases (typedefs):
and all of those with a leading u
for unsigned: uint8_t, …
Explanation
- Exact sizes (int8_t, …)
-
These are the exact size—no smaller, no bigger.
- Fastest at least this big (int_fast8_t, …)
-
The fastest type that can hold at least this many bits.
Speed matters; space doesn’t.
On a 64-bit computer that has to do extra work to simulate
16-bit overflow, it would be faster to use all 64 bits.
- Smallest at least this big (int_least8_t, …)
-
Space matters; speed doesn’t.
- Biggest signed integer (intmax_t)
-
I just want the biggest range this computer can offer.
- Holds a pointer (intptr_t)
-
I want to hold a pointer, or perhaps the difference between two
pointers.
Exact Types are Optional
- The following types are optional. If the computer can’t do
exactly this size, then the symbol isn’t defined.
Compilation fails; the programmer deals with it.
- On an old 32-bit computer, no int64_t.
- On a computer with only 64-bit types, no
int8_t, int16_t, and int32_t.
- On a computer with only 80-bit types, no
int8_t, int16_t, int32_t, and int64_t.
- On a computer with 32-bit integers, but a 64-bit address space,
no intptr_t.
Everything Else is Mandatory
- This implies that all the other types are mandatory:
- But, what if we’re on a pure 32-bit machine? We can’t do
int_fast64_t or int_least64_t!
- Sure, we can. Fake them in software. Add the lower 32 bits,
propagate the carry into the upper 32 bits, add them.
This is machine language, after all.
This Computer
cout << sizeof(int8_t) << '\n'
<< sizeof(int16_t) << '\n'
<< sizeof(int32_t) << '\n'
<< sizeof(int64_t) << '\n'
<< '\n'
<< sizeof(int_fast8_t) << '\n'
<< sizeof(int_fast16_t) << '\n'
<< sizeof(int_fast32_t) << '\n'
<< sizeof(int_fast64_t) << '\n'
<< '\n'
<< sizeof(int_least8_t) << '\n'
<< sizeof(int_least16_t) << '\n'
<< sizeof(int_least32_t) << '\n'
<< sizeof(int_least64_t) << '\n'
<< '\n'
<< sizeof(intmax_t) << '\n'
<< sizeof(intptr_t) << '\n';
1
2
4
8
1
8
8
8
1
2
4
8
8
8
Data Models
One speaks of a Data Model, e.g., LP64, which means
that Longs and Pointers are 64 bits wide.
#ifdef __LP64__ // non-standard
cout << "LP64\n";
#endif
LP64