01-typedef.c Shows how to use typedef to create a new type name. With the ability to create types comes the question of type compatibility. C basically follows the type name definitions down to the built-in type or struct type, whichever it is. For both, the usual conversion rules apply. For structs, C uses "name equivalence" (rather than "structural equivalence"). This means the two must have the same type name to be compatible - it's not enough that the struct definitions are structually identical. 02-fnPtr Function pointers are pointers that point to code. You can set them and you can invoke through them. The syntax to declare a function pointer type and a function pointer variable is very similar, and odd. 03-enum In C, an enum ISN'T a type, at least in the sense it is in Java. An enum is a way of creating many symbolic constants, as well as a type name. Enums act as int's, and can be used wherever an int could be used. So, they don't restrict values, say. Their benefit is mainly as documentation for human readers of the code. 04-max Here we use C preprocessor #define to create a macro. It does just what #define always does - causes the preprocessor to replace a string from the input file with another string (e.g., #define ONE 1 causes all occurences of "ONE" to be replaced by "1", as strings). We show an implementation of max(a,b) that has a common bug, and then fix it. Preprocessor macros are attractive for very short methods because they (a) look like method invocations in the source, so are natural to the human reader, and (b) have no procedure call overhead at run time, so are fast (especially for very short methods). 05-externalDef Macros can be defined as part of the compile command. Sometimes this gives more flexibility (like choosing to define DEBUG or not) without having to edit the code. 06-maxTyped What is happening here is looking forward to C++, rather than something very useful in C. Here we're trying to get the abstract max(a,b) function to check that the operands are type compatible. The preprocessor can't do type checking, but the compiler can. What we want are specialized versions of max(a,b), one for each type of operands we want to invoke max on. We do that by writing a macro that generates a specialized max function, given a type name. The user then invokes the macro (e.g., maxTypedTemplate(int) to generate the code of a C function max_int(int a, int b)). After that, s/he is able to invoked max_int() as normal.) It would be nice if the compiler just automated all this. That would allow for polymorphism. C can't automate it, but C++ can/does.