The Perils of typedef

The typedef keyword is both handy and dangerous. It’s handy because it allows the pantheon of C variable types to be expressed in different ways. It’s dangerous for the same reason.

In higher-level languages, variable types sprout like weeds in a garden. If you need a special variable type to describe a chunk of memory, that type is defined and used. In C, the type is an unsigned integer value that the typedef keyword creates: size_t. Here’s the statement that does so:

typedef unsigned long size_t

In the original K&R book, the justification for typedef is that it can create machine-specific variable types that are easily ported. For example, size_t might have been defined as an unsigned int for the old IBM PC, but it’s an unsigned long for current machines, or perhaps it’s even an unsigned long long. It doesn’t matter because the C language header file that defines size_t can be changed. The programmer just accepts the size_t variable as a valid type.

You can use typedef inside your code similar to the preprocessor directive #define, though typedef is handled by the compiler itself, not the preprocessor. Here’s the format:

typedef variable_type new_name

The variable_type is an existing C language variable, though it could also be an alias to that variable that typedef already created. The new_name is the alias. For example:

typedef char byte

Like a #define value, the typedef variable alias is valid only in the code where it’s created. Due to this limited scope, I encourage you to document the use of typedef within your code (or header file).

Most commonly, the typedef keyword is used to shorten structure definitions. For example:

typedef struct human {
    char *name;
    int age;
} person;

The struct human structure is aliased to person. So you can replace:

struct human myself;

with:

person myself;

In both examples, myself is a struct human structure variable.

The example given in the K&R manual uses typedef in the same statement that defines the structure, as shown above. I recommend using two statements instead:

struct human {
    char *name;
    int age;
};
typedef struct human person;

I believe this method is more readable, plus it avoids a common error made by budding programmers who become overly infatuated with typedef, especially with linked-lists and other self-referencing structures:

typedef struct greek {
    gr *prev;
    char *letter;
    gr *next;
} gr;

Above, the greek structure is aliased to gr; effectively struct greek is replaced by gr. The problem is that the new gr variable type is used inside the greek structure. Some compilers catch this error (using an alias before it’s defined), but some don’t.

The proper solution is to define the new gr structure variable like this:

struct greek {
    struct greek *prev;
    char *letter;
    struct greek *next;
};
typedef struct greek gr;

From this point on, you can use gr as a substitute for struct greek. Click here to view the double-linked list program from a previous Lesson, though in this Lesson’s code typedef is used to create a variable alias, gr. Judge for yourself whether it’s a useful trick.

Leave a Reply