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

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.


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


The syntax is of typedef is as follow:

typedef old_type new_type

In your first try, you defined the struct Book type and not Book. In other word, your data type is called struct Book and not Book.

In the second form, you used the right syntax of typedef, so the compiler recognizes the type called Book.


Want to add by clarifying when you actually declare a variable.

struct foo {
   int a;
} my_foo;

defines foo and immediately declares a variable my_foo of the struct foo type, meaning you can use it like this my_foo.a = 5;

However, because typedef syntax follows typedef <oldname> <newname>

typedef struct bar {
   int b;
} my_bar;

is not declaring a variable my_bar of type struct bar, my_bar.b = 5; is illegal. It is instead giving a new name to the struct bar type in the form of my_bar. You can now declare the struct bar type with my_bar like this:

my_bar some_bar;

The other answers are all correct and useful, but maybe longer that necessary. Do this:

typedef struct Book Book;
typedef struct Books Books;
typedef struct Author Author;

struct Book {
    ... as you wish ...
};

struct Author {
    ... as you wish ...
};

struct Books {
    ... as you wish ...
};

You can define the your struct's in any order provided they only contain pointers to other struct's.