typedef struct vs struct definitions
The common idiom is using both:
typedef struct S {
int x;
} S;
They are different definitions. To make the discussion clearer I will split the sentence:
struct S {
int x;
};
typedef struct S S;
In the first line you are defining the identifier S
within the struct name space (not in the C++ sense). You can use it and define variables or function arguments of the newly defined type by defining the type of the argument as struct S
:
void f( struct S argument ); // struct is required here
The second line adds a type alias S
in the global name space and thus allows you to just write:
void f( S argument ); // struct keyword no longer needed
Note that since both identifier name spaces are different, defining S
both in the structs and global spaces is not an error, as it is not redefining the same identifier, but rather creating a different identifier in a different place.
To make the difference clearer:
typedef struct S {
int x;
} T;
void S() { } // correct
//void T() {} // error: symbol T already defined as an alias to 'struct S'
You can define a function with the same name of the struct as the identifiers are kept in different spaces, but you cannot define a function with the same name as a typedef
as those identifiers collide.
In C++, it is slightly different as the rules to locate a symbol have changed subtly. C++ still keeps the two different identifier spaces, but unlike in C, when you only define the symbol within the class identifier space, you are not required to provide the struct/class keyword:
// C++
struct S {
int x;
}; // S defined as a class
void f( S a ); // correct: struct is optional
What changes are the search rules, not where the identifiers are defined. The compiler will search the global identifier table and after S
has not been found it will search for S
within the class identifiers.
The code presented before behaves in the same way:
typedef struct S {
int x;
} T;
void S() {} // correct [*]
//void T() {} // error: symbol T already defined as an alias to 'struct S'
After the definition of the S
function in the second line, the struct S
cannot be resolved automatically by the compiler, and to create an object or define an argument of that type you must fall back to including the struct
keyword:
// previous code here...
int main() {
S();
struct S s;
}
struct
and typedef
are two very different things.
The struct
keyword is used to define, or to refer to, a structure type. For example, this:
struct foo {
int n;
};
creates a new type called struct foo
. The name foo
is a tag; it's meaningful only when it's immediately preceded by the struct
keyword, because tags and other identifiers are in distinct name spaces. (This is similar to, but much more restricted than, the C++ concept of namespace
s.)
A typedef
, in spite of the name, does not define a new type; it merely creates a new name for an existing type. For example, given:
typedef int my_int;
my_int
is a new name for int
; my_int
and int
are exactly the same type. Similarly, given the struct
definition above, you can write:
typedef struct foo foo;
The type already has a name, struct foo
. The typedef
declaration gives the same type a new name, foo
.
The syntax allows you to combine a struct
and typedef
into a single declaration:
typedef struct bar {
int n;
} bar;
This is a common idiom. Now you can refer to this structure type either as struct bar
or just as bar
.
Note that the typedef name doesn't become visible until the end of the declaration. If the structure contains a pointer to itself, you have use the struct
version to refer to it:
typedef struct node {
int data;
struct node *next; /* can't use just "node *next" here */
} node;
Some programmers will use distinct identifiers for the struct tag and for the typedef name. In my opinion, there's no good reason for that; using the same name is perfectly legal and makes it clearer that they're the same type. If you must use different identifiers, at least use a consistent convention:
typedef struct node_s {
/* ... */
} node;
(Personally, I prefer to omit the typedef
and refer to the type as struct bar
. The typedef
save a little typing, but it hides the fact that it's a structure type. If you want the type to be opaque, this can be a good thing. If client code is going to be referring to the member n
by name, then it's not opaque; it's visibly a structure, and in my opinion it makes sense to refer to it as a structure. But plenty of smart programmers disagree with me on this point. Be prepared to read and understand code written either way.)
(C++ has different rules. Given a declaration of struct blah
, you can refer to the type as just blah
, even without a typedef. Using a typedef might make your C code a little more C++-like -- if you think that's a good thing.)
Another difference not pointed out is that giving the struct a name (i.e. struct myStruct) also enables you to provide forward declarations of the struct. So in some other file, you could write:
struct myStruct;
void doit(struct myStruct *ptr);
without having to have access to the definition. What I recommend is you combine your two examples:
typedef struct myStruct{
int one;
int two;
} myStruct;
This gives you the convenience of the more concise typedef name but still allows you to use the full struct name if you need.