C : typedef struct name {...}; VS typedef struct{...} name;
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;
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 declare the types before using them. More important though is to understand the syntax of 3 things:
- definition of struct type,
- definition and declaration of struct variable, and
- typedef
(Note that in the C-programming language, definition and declaration usually happen at the same time, and thus are essentially the same. This is not the case in many other languages. See footnote below for further details.)
When defining a struct, the struct can be tagged (named), or untagged (if untagged, then the struct 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 define a struct variable/instance:
struct Name myNameStruct;
This defines a variable called myNameStruct
which is a struct of type struct Name
.
You can also define a struct, and declare/define a struct variable at the same time:
struct Name {
...
} myNameStruct;
As before, this defines a variable called myNameStruct
which is an instance of type struct Name
... But it does it at the same time it defines the type struct Name
.
The type can then be used again to declare and define 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 and defining 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 define 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 tagging (naming) the struct. This is useful for self-referential structs (for example linked-list nodes), but is otherwise superfluous. None-the-less, many follow the practice of always tagging structs, as in this example:
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/defining 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 tag (name) the struct type at the time you define it, then you must use it immediately, either to define a variable:
struct {
...
} myNameStruct; // defines myNameStruct as a variable with this struct
// definition, but the struct definition cannot be re-used.
Or you can use an untagged struct type inside 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
Footnote about the differences between declaring and defining: First a special thanks to @CJM for suggesting clarifying edits, particularly in relation to the use of these terms. The following items are typically declared and defined: types, variables, and functions.
- Declaring gives the compiler only a symbolic name and a "type" for that symbolic name.
- For example, declaring a variable tells the compiler the name of that variable, and its type.
- Defining gives the complier the full details of an item:
- In the case of a type, defining gives the compiler both a name, and the detailed structure for that type.
- In the case of a variable, defining tells the compiler to allocate memory (where and how much) to create an instance of that variable.
Generally speaking, in a program made up of multiple files, the variables, types and functions may be declared in many files, but each may have only one definition.
In many programming languages (for example C++) declaration and definition are easily separated. This permits "forward declaration" of types, variables, and functions, which can allow files to compile without the need for these items to be defined until later. In the C programming language however declaration and definition of variables are one and the same. (The only exception, that I know of, in the C programming language, is the use of keyword extern
to allow a variable to be declared without being defined.)
It is for this reason that in a previous edit of this answer I referred to "definition of structs" and "declaration of struct [variables]," where the meaning of "declaration of a struct [variable]" was understood to be creating an instance (variable) of that struct.
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
.