C : typedef struct name {...}; VS typedef struct{...} name;

Alek Sobczyk picture Alek Sobczyk · Jul 18, 2013 · Viewed 42.9k times · Source

As the title says, I have this code:

    typedef struct Book{
        int id;
        char title[256];
        char summary[2048];
        int numberOfAuthors;
        struct Author *authors;
    };


    typedef struct Author{
        char firstName[56];
        char lastName[56];
    };


    typedef struct Books{
        struct Book *arr;
        int numberOfBooks;
    };

I get these errors from gcc :

bookstore.c:8:2: error: unknown type name ‘Author’
bookstore.c:9:1: warning: useless storage class specifier in empty declaration [enabled by default]
bookstore.c:15:1: warning: useless storage class specifier in empty declaration [enabled by default]
bookstore.c:21:2: error: unknown type name ‘Book’
bookstore.c:23:1: warning: useless storage class specifier in empty declaration [enabled by default]

No warnings and no errors occur if I change the typedefs like this:

    typedef struct{
        char firstName[56];
        char lastName[56];
    } Author;

Having searched through C Programming Language, 2nd Edition and googled for a couple of hours, I can't figure out why the first implementation won't work.

Answer

Daniel Goldfarb picture Daniel Goldfarb · May 14, 2014

There are several things going on here. First, as others have said, the compiler's complaint about unknown type may be because you need to define the types before using them. More important though is to understand the syntax of 3 things: (1) struct definition, (2) struct declaration, and (3) typedef.

When Defining a struct, the struct can be named, or unnamed (if unnamed, then it must be used immediately (will explain what this means further below)).

struct Name {
   ...
};

This defines a type called "struct Name" which then can be used to Declare a struct variable:

struct Name myNameStruct;

This declares a variable called myNameStruct which is a struct of type struct Name.

You can also Define a struct, and declare a struct variable at the same time:

struct Name {
   ...
} myNameStruct;

As before, this declares a variable called myNameStruct which is a struct of type struct Name ... But it does it at the same time it defines the type struct Name.
The type can be used again to declare another variable:

struct Name myOtherNameStruct;

Now typedef is just a way to alias a type with a specific name:

typedef OldTypeName NewTypeName;

Given the above typedef, any time you use NewTypeName it is the same as using OldTypeName. In the C programming language this is particularly useful with structs, because it gives you the ability to leave off the word "struct" when declaring variables of that type and to treat the struct's name simply as a type on its own (as we do in C++). Here is an example that first Defines the struct, and then typedefs the struct:

struct Name {
   ...
};

typedef struct Name Name_t;

In the above OldTypeName is struct Name and NewTypeName is Name_t. So now, to declare a variable of type struct Name, instead of writing:

struct Name myNameStruct;

I can simple write:

Name_t myNameStruct;

NOTE ALSO, the typedef CAN BE COMBINED with the struct definition, and this is what you are doing in your code:

typedef struct {
   ...
} Name_t;

This can also be done while naming the struct, but this is superfluous:

typedef struct Name {
   ...
} Name_t;

NOTE WELL: In the syntax above, since you have started with "typedef" then the whole statement is a typedef statement, in which the OldTypeName happens to be a struct definition. Therefore the compiler interprets the name coming after the right curly brace } as the NewTypeName ... it is NOT the variable name (as it would be in the syntax without typedef, in which case you would be defining the struct and declaring a struct variable at the same time).

Furthermore, if you state typedef, but leave off the Name_t at then end, then you have effectively created an INCOMPLETE typedef statement, because the compiler considers everything within "struct Name { ... }" as OldTypeName, and you are not providing a NewTypeName for the typedef. This is why the compiler is not happy with the code as you have written it (although the compiler's messages are rather cryptic because it's not quite sure what you did wrong).

Now, as I noted above, if you do not name the struct type at the time you define it, then you must use it immediately either to declare a variable:

struct {
   ...
} myNameStruct;  // declares myNameStruct as a variable with this struct
                 // definition, but the definition cannot be re-used.

Or you can use an unnamed struct type in a typedef:

typedef struct {
   ...
} Name_t;

This final syntax is what you actually did when you wrote:

typedef struct{
   char firstName[56];
   char lastName[56];
} Author;

And the compiler was happy. HTH.

Regarding the comment/question about the _t suffix:

_t suffix is a convention, to indicate to people reading the code that the symbolic name with the _t is a Type name (as opposed to a variable name). The compiler does not parse, nor is it aware of, the _t.

The C89, and particularly the C99, standard libraries defined many types AND CHOSE TO USE the _t for the names of those types. For example C89 standard defines wchar_t, off_t, ptrdiff_t. The C99 standard defines a lot of extra types, such as uintptr_t, intmax_t, int8_t, uint_least16_t, uint_fast32_t, etc. But _t is not reserved, nor specially parsed, nor noticed by the compiler, it is merely a convention that is good to follow when you are defining new types (via typedef) in C. In C++ many people use the convention to start type names with an uppercase, for example, MyNewType ( as opposed to the C convention my_new_type_t ). HTH