The keyword typedef is used similarly to the storage class keywords, and is sometimes classified as a storage class. What it is used for is to declare synonyms for types, either elementary or compound. A typedef declaration does not create new types. It only creates an alias or alternative and usually simpler way to make declarations.
The general form of a typedef declaration is:
typedef type_specifier identifier_list;
where: type_specifier is some existing type, and identifier_list is a list of one or more comma separated identifiers which become synonyms for type_specifier. For example:
typedef unsigned char uchar; uchar byte, *zp;
has resulted in the identifier uchar begin defined as a shorter alternative for the type unsigned char, with the identifier byte being a variable of type unsigned char and zp as of type pointer to unsigned char.
A typedef declaration can be used to make synonyms for any type, including: structures, unions, pointers to functions and data pointer types. When used for these it can save a lot of keystrokes when entering the source program with a gain in clarity.
If you truly want a new type so that the compiler will not allow variables of different types to be assigned to each other or used in the palace of another without giving a warning or error message, then the only way is with unions and structures (even if they have only one field).
Once a synonym has been declared, it can be used in another declaration as shown, or the synonym declaration can be combined with the const and volatile modifiers (or any implementation extensions).