Why do C programmers use typedefs to rename basic types?
So I'm far from an expert on C, but something's been bugging me about code I've been reading for a long time: can someone explain to me why C(++) programmers use typedefs to rename simple types? I understand why you would use them for structs, but what exactly is the reason for declarations I see like
typedef unsigned char uch;
typedef uch UBYTE;
typedef unsigned long ulg;
typedef unsigned int u32;
typedef signed short s16;
Is there some advantage to this that isn't clear to me (a programmer whose experience begins with Java and hasn't ventured far outside of strictly type-safe languages)? Because I can't think of any reason for it--it looks like it would just make the code less readable for people unfamiliar with the project.
Feel free to treat me like a C newbie, I honestly know very little about it and it's likely there are things I've misunderstood from the outset. ;)
Renaming types without changing their exposed semantics/characteristics doesn't make much sense. In your example
typedef unsigned char uch;
typedef unsigned long ulg;
belong to that category. I don't see the point, aside from making a shorter name.
But these ones
typedef uch UBYTE;
typedef unsigned int u32;
typedef signed short s16;
are a completely different story. For example, s16
stands for "signed 16 bit type". This type is not necessarily signed short
. Which specific type will hide behind s16
is platform-dependent. Programmers introduce this extra level of naming indirection to simplify the support for multiple platforms. If on some other platform signed 16 bit type happens to be signed int
, the programmer will only have to change one typedef definition. UBYTE
apparently stands for an unsigned machine byte type, which is not necessarily unsigned char
.
It's worth noting that the C99 specification already provides a standard nomenclature for integral types of specific width, like int16_t
, uint32_t
and so on. It probably makes more sense to stick with this standard naming convention on platforms that don't support C99.
This allows for portability. For example you need an unsigned 32-bit integer type. Which standard type is that? You don't know - it's implementation defined. That's why you typedef
a separate type to be 32-bit unsigned integer and use the new type in your code. When you need to compile on another C implementation you just change the typedef
s.
Sometimes it is used to reduce an unwieldy thing like volatile unsigned long
to something a little more compact such as vuint32_t
.
Other times it is to help with portability since types like int
are not always the same on each platform. By using a typedef you can set the storage class you are interested in to the platform's closest match without changing all the source code.