The purpose of it is to make pid_t
, or any other type of the sort, platform-independent, such that it works properly regardless of how it's actually implemented. This practice is used for any type that needs to be platform-independent, such as:
pid_t
: Has to be large enough to store a PID on the system you're coding for. Maps to int
as far as I'm aware, although I'm not the most familiar with the GNU C library.
size_t
: An unsigned
variable able to store the result of the sizeof
operator. Generally equal in size to the word size of the system you're coding for.
int16_t
(intX_t
): Has to be exactly 16 bits, regardless of platform, and won't be defined on platforms that don't use 2n-bit bytes (typically 8- or 16-bit) or, much less frequently, provide a means of accessing exactly 16 bits out of a larger type (e.g., the PDP-10's "bytes", which could be any number of contiguous bits out of a 36-bit word, and thus could be exactly 16 bits), and thus don't support 16-bit two's complement integer types (such as a 36-bit system). Generally maps to short
on modern computers, although it may be an int
on older ones.
int_least32_t
(int_leastX_t
): Has to be the smallest size possible that can store at least 32 bits, such as 36 bits on a 36-bit or 72-bit system. Generally maps to int
on modern computers, although it may be a long
on older ones.
int_fastX_t
: Has to be the fastest type possible that can store at least X bits. Generally, it's the system's word size if (X <= word_size)
(or sometimes char
for int_fast8_t
), or acts like int_leastX_t
if (X > word_size)
)
intmax_t
: Has to be the maximum integer width supported by the system. Generally, it'll be at least 64 bits on modern systems, although some systems may support extended types larger than long long
(and if so, intmax_t
is required to be the largest of those types).
- And more...
Mechanically, it allows the compiler's installer to typedef
the appropriate type to the identifier (whether a standard type or an awkwardly-named internal type) behind the scenes, whether by creating appropriate header files, coding it into the compiler's executable, or some other method. For example, on a 32-bit system, Microsoft Visual Studio will implement the intX_t
and similar types as follows (note: comments added by me):
// Signed ints of exactly X bits.
typedef signed char int8_t;
typedef short int16_t;
typedef int int32_t;
// Unsigned ints of exactly X bits.
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
// Signed ints of at least X bits.
typedef signed char int_least8_t;
typedef short int_least16_t;
typedef int int_least32_t;
// Unsigned ints of at least X bits.
typedef unsigned char uint_least8_t;
typedef unsigned short uint_least16_t;
typedef unsigned int uint_least32_t;
// Speed-optimised signed ints of at least X bits.
// Note that int_fast16_t and int_fast32_t are both 32 bits, as a 32-bit processor will generally operate on a full word faster than a half-word.
typedef char int_fast8_t;
typedef int int_fast16_t;
typedef int int_fast32_t;
// Speed-optimised unsigned ints of at least X bits.
typedef unsigned char uint_fast8_t;
typedef unsigned int uint_fast16_t;
typedef unsigned int uint_fast32_t;
typedef _Longlong int64_t;
typedef _ULonglong uint64_t;
typedef _Longlong int_least64_t;
typedef _ULonglong uint_least64_t;
typedef _Longlong int_fast64_t;
typedef _ULonglong uint_fast64_t;
On a 64-bit system, however, they may not necessarily be implemented the same way, and I can guarantee that they won't be implemented the same way on an archaic 16-bit system, assuming you can find a version of MSVS compatible with one.
Overall, it allows code to work properly regardless of the specifics of your implementation, and to meet the same requirements on any standards-compatible system (e.g. pid_t
can be guaranteed to be large enough to hold any valid PID on the system in question, no matter what system you're coding for). It also prevents you from having to know the nitty-gritty, and from having to look up internal names you may not be familiar with. In short, it makes sure your code works the same regardless of whether pid_t
(or any other similar typedef) is implemented as an int
, a short
, a long
, a long long
, or even a __Did_you_really_just_dare_me_to_eat_my_left_shoe__
, so you don't have to.
Additionally, it serves as a form of documentation, allowing you to tell what a given variable is for at a glance. Consider the following:
int a, b;
....
if (a > b) {
// Nothing wrong here, right? They're both ints.
}
Now, let's try that again:
size_t a;
pid_t b;
...
if (a > b) {
// Why are we comparing sizes to PIDs? We probably messed up somewhere.
}
If used as such, it can help you locate potentially problematic segments of code before anything breaks, and can make troubleshooting much easier than it would otherwise be.