Declare data type structure [duplicate] - c

This question already has answers here:
Why should we typedef a struct so often in C?
(15 answers)
Closed 6 years ago.
I'm a beginner in C programming, but I was wondering what's the difference between using typedef when defining a structure versus not using typedef. It seems to me like there's really no difference, they accomplish the same goal.
struct myStruct{
int one;
int two;
};
vs.
typedef struct{
int one;
int two;
}myStruct;

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 namespaces.)
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 saves 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.

In C (not C++), you have to declare struct variables like:
struct myStruct myVariable;
In order to be able to use myStruct myVariable; instead, you can typedef the struct:
typedef struct myStruct someStruct;
someStruct myVariable;
You can combine struct definition and typedefs it in a single statement which declares an anonymous struct and typedefs it.
typedef struct { ... } myStruct;

If you use struct without typedef, you'll always have to write
struct mystruct myvar;
It's illegal to write
mystruct myvar;
If you use the typedef you don't need the struct prefix anymore.

In C, the type specifier keywords of structures, unions and enumerations are mandatory, ie you always have to prefix the type's name (its tag) with struct, union or enum when referring to the type.
You can get rid of the keywords by using a typedef, which is a form of information hiding as the actual type of an object will no longer be visible when declaring it.
It is therefore recommended (see eg the Linux kernel coding style guide, Chapter 5) to only do this when
you actually want to hide this information and not just to save a few keystrokes.
An example of when you should use a typedef would be an opaque type which is only ever used with corresponding accessor functions/macros.

You can't use forward declaration with the typedef struct.
The struct itself is an anonymous type, so you don't have an actual name to forward declare.
typedef struct{
int one;
int two;
} myStruct;
A forward declaration like this won't work:
struct myStruct; //forward declaration fails
void blah(myStruct* pStruct);
//error C2371: 'myStruct' : redefinition; different basic types

The following code creates an anonymous struct with the alias myStruct:
typedef struct{
int one;
int two;
} myStruct;
You can't refer it without the alias because you don't specify an identifier for the structure.

The difference comes in when you use the struct.
The first way you have to do:
struct myStruct aName;
The second way allows you to remove the keyword struct.
myStruct aName;

The typedef, as it is with other constructs, is used to give a data type a new name. In this case it is mostly done in order to make the code cleaner:
struct myStruct blah;
vs.
myStruct blah;

I see some clarification is in order on this. C and C++ do not define types differently. C++ was originally nothing more than an additional set of includes on top of C.
The problem that virtually all C/C++ developers have today, is a) universities are no longer teaching the fundamentals, and b) people don't understand the difference between a definition and a declaration.
The only reason such declarations and definitions exist is so that the linker can calculate address offsets to the fields in the structure. This is why most people get away with code that is actually written incorrectly-- because the compiler is able to determine addressing. The problem arises when someone tries to do something advance, like a queue, or a linked list, or piggying-backing an O/S structure.
A declaration begins with 'struct', a definition begins with 'typedef'.
Further, a struct has a forward declaration label, and a defined label. Most people don't know this and use the forward declaration label as a define label.
Wrong:
struct myStruct
{
int field_1;
...
};
They've just used the forward declaration to label the structure-- so now the compiler is aware of it-- but it isn't an actual defined type. The compiler can calculate the addressing-- but this isn't how it was intended to be used, for reasons I will show momentarily.
People who use this form of declaration, must always put 'struct' in practicly every reference to it-- because it isn't an offical new type.
Instead, any structure that does not reference itself, should be declared and defined this way only:
typedef struct
{
field_1;
...
}myStruct;
Now it's an actual type, and when used you can use at as 'myStruct' without having to prepend it with the word 'struct'.
If you want a pointer variable to that structure, then include a secondary label:
typedef struct
{
field_1;
...
}myStruct,*myStructP;
Now you have a pointer variable to that structure, custom to it.
FORWARD DECLARATION--
Now, here's the fancy stuff, how the forward declaration works. If you want to create a type that refers to itself, like a linked list or queue element, you have to use a forward declaration. The compiler doesn't consider the structure defined until it gets to the semicolon at the very end, so it's just declared before that point.
typedef struct myStructElement
{
myStructElement* nextSE;
field_1;
...
}myStruct;
Now, the compiler knows that although it doesn't know what the whole type is yet, it can still reference it using the forward reference.
Please declare and typedef your structures correctly. There's actually a reason.

With the latter example you omit the struct keyword when using the structure. So everywhere in your code, you can write :
myStruct a;
instead of
struct myStruct a;
This save some typing, and might be more readable, but this is a matter of taste

Related

Different types of Structure Declaration in C [duplicate]

This question already has answers here:
Why should we typedef a struct so often in C?
(15 answers)
Closed 6 years ago.
I'm a beginner in C programming, but I was wondering what's the difference between using typedef when defining a structure versus not using typedef. It seems to me like there's really no difference, they accomplish the same goal.
struct myStruct{
int one;
int two;
};
vs.
typedef struct{
int one;
int two;
}myStruct;
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 namespaces.)
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 saves 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.
In C (not C++), you have to declare struct variables like:
struct myStruct myVariable;
In order to be able to use myStruct myVariable; instead, you can typedef the struct:
typedef struct myStruct someStruct;
someStruct myVariable;
You can combine struct definition and typedefs it in a single statement which declares an anonymous struct and typedefs it.
typedef struct { ... } myStruct;
If you use struct without typedef, you'll always have to write
struct mystruct myvar;
It's illegal to write
mystruct myvar;
If you use the typedef you don't need the struct prefix anymore.
In C, the type specifier keywords of structures, unions and enumerations are mandatory, ie you always have to prefix the type's name (its tag) with struct, union or enum when referring to the type.
You can get rid of the keywords by using a typedef, which is a form of information hiding as the actual type of an object will no longer be visible when declaring it.
It is therefore recommended (see eg the Linux kernel coding style guide, Chapter 5) to only do this when
you actually want to hide this information and not just to save a few keystrokes.
An example of when you should use a typedef would be an opaque type which is only ever used with corresponding accessor functions/macros.
You can't use forward declaration with the typedef struct.
The struct itself is an anonymous type, so you don't have an actual name to forward declare.
typedef struct{
int one;
int two;
} myStruct;
A forward declaration like this won't work:
struct myStruct; //forward declaration fails
void blah(myStruct* pStruct);
//error C2371: 'myStruct' : redefinition; different basic types
The following code creates an anonymous struct with the alias myStruct:
typedef struct{
int one;
int two;
} myStruct;
You can't refer it without the alias because you don't specify an identifier for the structure.
The difference comes in when you use the struct.
The first way you have to do:
struct myStruct aName;
The second way allows you to remove the keyword struct.
myStruct aName;
The typedef, as it is with other constructs, is used to give a data type a new name. In this case it is mostly done in order to make the code cleaner:
struct myStruct blah;
vs.
myStruct blah;
I see some clarification is in order on this. C and C++ do not define types differently. C++ was originally nothing more than an additional set of includes on top of C.
The problem that virtually all C/C++ developers have today, is a) universities are no longer teaching the fundamentals, and b) people don't understand the difference between a definition and a declaration.
The only reason such declarations and definitions exist is so that the linker can calculate address offsets to the fields in the structure. This is why most people get away with code that is actually written incorrectly-- because the compiler is able to determine addressing. The problem arises when someone tries to do something advance, like a queue, or a linked list, or piggying-backing an O/S structure.
A declaration begins with 'struct', a definition begins with 'typedef'.
Further, a struct has a forward declaration label, and a defined label. Most people don't know this and use the forward declaration label as a define label.
Wrong:
struct myStruct
{
int field_1;
...
};
They've just used the forward declaration to label the structure-- so now the compiler is aware of it-- but it isn't an actual defined type. The compiler can calculate the addressing-- but this isn't how it was intended to be used, for reasons I will show momentarily.
People who use this form of declaration, must always put 'struct' in practicly every reference to it-- because it isn't an offical new type.
Instead, any structure that does not reference itself, should be declared and defined this way only:
typedef struct
{
field_1;
...
}myStruct;
Now it's an actual type, and when used you can use at as 'myStruct' without having to prepend it with the word 'struct'.
If you want a pointer variable to that structure, then include a secondary label:
typedef struct
{
field_1;
...
}myStruct,*myStructP;
Now you have a pointer variable to that structure, custom to it.
FORWARD DECLARATION--
Now, here's the fancy stuff, how the forward declaration works. If you want to create a type that refers to itself, like a linked list or queue element, you have to use a forward declaration. The compiler doesn't consider the structure defined until it gets to the semicolon at the very end, so it's just declared before that point.
typedef struct myStructElement
{
myStructElement* nextSE;
field_1;
...
}myStruct;
Now, the compiler knows that although it doesn't know what the whole type is yet, it can still reference it using the forward reference.
Please declare and typedef your structures correctly. There's actually a reason.
With the latter example you omit the struct keyword when using the structure. So everywhere in your code, you can write :
myStruct a;
instead of
struct myStruct a;
This save some typing, and might be more readable, but this is a matter of taste

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 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.
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.
You just need to define Author before defining Book.
You use Author in Book so it needs to be defined before.
I think is going to help you understand.
http://www.tutorialspoint.com/cprogramming/c_typedef.htm
bookstore.c:8:2: error: unknown type name ‘Author’
bookstore.c:21:2: error: unknown type name ‘Book’
These are produced because you have to define them before you use them. Move the struct "Author" & "Books" above the struct "Book". This will solve it.
Also the warning you are getting explains why there is a problem, the compiler identifies "typedef struct Author" as not necessary because you are not properly typedef the struct so there is nothing useful for the compiler to "read".
Since you already know the answer should be in this form
typedef struct {
...
...
...
} struct-name;
stick with that.

What exactly does this syntax do? (in relation to c-style structs)

I understand the whole typedef-ing a struct in C concept so that you can avoid using the keyword struct whenever you use it. I'm still a little confused about what's going on here though.
Can someone tell me the various things this structure definition is doing?
typedef struct work_tag {
//contents.
} work_t, *work_p;
It defines two typedefs, like:
typedef struct work_tag {
//contents.
} work_t;
typedef struct work_tag *work_p;
As the other answers say, it defines two typedefs, one named work_t that refers to struct work_tag, and another name work_p that refers to struct work_tag*.
Note that a typedef does not create a new type. All it does is create an alias for an existing type. struct work_tag and work_t are not two similar types, they're two names for exactly the same type.
Now let's discuss why you'd want to do this.
The types struct work_tag and struct work_tag* already have perfectly good names. A typedef gives you a way to refer to those types using a single identifier, but in my opinion that's really not much of an advantage. And a typedef for a pointer type can actually be a bit dangerous. If you want to define a name for a truly opaque type, where code that uses it doesn't take advantage of the fact that it's a struct or a pointer, a typedef is a good solution; otherwise, you're just obscuuring important information.
I'd just write:
struct work {
// contents
};
and then refer to the type as struct work, and to a pointer to the type as struct work*.
But if you really feel the need to have a one-word name for the type, there's no need to use different names for the tag and the typedef:
typedef struct work {
// contents
} work;
Now you can refer to the type either as struct work or as work, and to the pointer type either as struct work* or as work*. (C++ does this implicitly; C does not.) Note that if a struct work contains a pointer to another struct work, you can't use the typedef name inside the definition; the typedef name doesn't become visible until the end of definition.
Think of a typedef like a variable declaration. Just like you can do int a, b to make two int variables, you can do typedef int a_t, b_t to make two types in a single typedef.
It's assigning two alternative names to existing types:
work_t -> struct work_tag
work_p -> struct work_tag *

What are the differences between these two typedef styles in C?

I'm curious what the difference here is when typedefing an enum or struct. Is there any difference semantically between these two blocks?
This:
typedef enum { first, second, third } SomeEnum;
and this:
enum SomeEnum { first, second, third };
typedef enum SomeEnum SomeEnum;
Same deal for structs. I've seen both in use, and they both seem to do the same thing in C or Objective-C. Is there a real difference or is it just a preference for which style you can use?
The difference is that the second approach declares a type named enum SomeEnum and also declares a typedef-name SomeEnum - an alias for that type. It can actually be combined into the equivalent one-liner
typedef enum SomeEnum { first, second, third } SomeEnum;
which makes it rather obvious that the only difference between the two approaches is whether there's a name after the enum keyword. With the second approach, you can declare object of that enum type by using either SomeEnum e or enum SomeEnum e, whichever you prefer.
The first approach only declares the typedef-name SomeEnum for an originally anonymous enum type, meaning that you are limited to SomeEnum e declarations.
So, as long as you only use the typedef-name SomeEnum in your declarations, there will be no difference between the two. However, in some cases you might have to use the full original name of the type enum SomeEnum. In the first approach that name is not available, so you'll be out of luck.
For example, if after the above declaration you also declare a variable named SomeEnum in some nested scope
int SomeEnum;
the name of the variable will hide the typedef-name of the enum, thus making this declaration illegal
SomeEnum e; /* ERROR: `SomeEnum` is not a type */
However, if you used the second approach when declaring your enum, you can work around this problem by using the full type name
enum SomeEnum e; /* OK */
This would not be possible if you used the first approach when declaring your enum type.
When used with structs, the name after the struct is a must when you need a self-referencing type (a type that contains a pointer to the same type), like
typedef struct SomeStruct {
struct SomeStruct *next;
} SomeStruct;
Finally, in the second approach the typedef name is totally optional. You can simply declare
enum SomeEnum { first, second, third };
and just use enum SomeEnum every time you need to refer to this type.
Yes, there is a semantic difference. The second snippet declares a tag identifier, but the first doesn't. Both declare an ordinary identifier.
That means that for the first, this code is not valid, but for the second, it is:
enum SomeEnum foo;
As far as i know, there is no other semantic difference between them in your code. For structs and unions, the second form, maybe combined with the typedef in one declaration, is needed for recursive types
typedef struct node {
struct node *parent; // refer to the tag identifier
} node;
The ordinary identifier is not yet visible in the struct's specifier, and thus you need to refer to the struct by the already declared tag identifier. Tag identifiers are referred to by prepending them by "struct", "union" or "enum", while ordinary identifiers are referred to without a prefix (thus the name "ordinary").
Besides separating the identifiers that refer to structs, unions and enumerations from those that refer to values, tag identifiers are also useful for creating forward declarations:
/* forward declaration */
struct foo;
/* for pointers, forward declarations are entirely sufficient */
struct foo *pfoo = ...;
/* ... and then later define its contents */
struct foo {
/* ... */
};
Typedef names can't be declared repeatedly at the same scope (as opposed to C++ where they can), and they need to refer to an existing type, so that they cannot be used to create forward declarations.
The only real difference is that in the second case, you can use something like:
enum SomeEnum x;
whereas the first only supports:
SomeEnum x;
To people who've been writing C a long time, defining a struct without the struct keyword often "feels" strange...
The first form creates an anonymous enum type and creates a SomeEnum alias to it.
The second form creates both a enum SomeEnum type and a SomeEnum alias to it.
(In C, there are separate namespaces for types. That is, struct Foo is different from enum Foo which is different from Foo.)
This is more important for structs than enums since you'd need to use the second form if your struct were self-referential. For example:
struct LinkedListNode
{
void* item;
struct LinkedListNode* next;
};
typedef struct LinkedListNode LinkedListNode;
The above wouldn't be possible with the first form.
For structs there's a real difference that isn't simply about naming.
This is valid C:
struct SomeEnum { struct SomeEnum *first; };
This is not:
typedef struct { SomeEnum *first; } SomeEnum;
Adding to user207442's comment, it's possible for a source code module to declare variables of type "struct foo *" without ever having a definition for the struct. Such a module will not be able to dereference such pointers, but may pass them to and from other modules.
For example, one could have a header file define a type "USERCONSOLE" using "typedef struct _USERCONSOLE *USERCONSOLE;". Code that #include's that header file could have variables of type USERCONSOLE, and pass such variables to/from modules that know what a _USERCONSOLE really is, without the header file having to expose the actual definition of the structure.

typedef struct vs struct definitions [duplicate]

This question already has answers here:
Why should we typedef a struct so often in C?
(15 answers)
Closed 6 years ago.
I'm a beginner in C programming, but I was wondering what's the difference between using typedef when defining a structure versus not using typedef. It seems to me like there's really no difference, they accomplish the same goal.
struct myStruct{
int one;
int two;
};
vs.
typedef struct{
int one;
int two;
}myStruct;
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 namespaces.)
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 saves 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.
In C (not C++), you have to declare struct variables like:
struct myStruct myVariable;
In order to be able to use myStruct myVariable; instead, you can typedef the struct:
typedef struct myStruct someStruct;
someStruct myVariable;
You can combine struct definition and typedefs it in a single statement which declares an anonymous struct and typedefs it.
typedef struct { ... } myStruct;
If you use struct without typedef, you'll always have to write
struct mystruct myvar;
It's illegal to write
mystruct myvar;
If you use the typedef you don't need the struct prefix anymore.
In C, the type specifier keywords of structures, unions and enumerations are mandatory, ie you always have to prefix the type's name (its tag) with struct, union or enum when referring to the type.
You can get rid of the keywords by using a typedef, which is a form of information hiding as the actual type of an object will no longer be visible when declaring it.
It is therefore recommended (see eg the Linux kernel coding style guide, Chapter 5) to only do this when
you actually want to hide this information and not just to save a few keystrokes.
An example of when you should use a typedef would be an opaque type which is only ever used with corresponding accessor functions/macros.
You can't use forward declaration with the typedef struct.
The struct itself is an anonymous type, so you don't have an actual name to forward declare.
typedef struct{
int one;
int two;
} myStruct;
A forward declaration like this won't work:
struct myStruct; //forward declaration fails
void blah(myStruct* pStruct);
//error C2371: 'myStruct' : redefinition; different basic types
The following code creates an anonymous struct with the alias myStruct:
typedef struct{
int one;
int two;
} myStruct;
You can't refer it without the alias because you don't specify an identifier for the structure.
The difference comes in when you use the struct.
The first way you have to do:
struct myStruct aName;
The second way allows you to remove the keyword struct.
myStruct aName;
The typedef, as it is with other constructs, is used to give a data type a new name. In this case it is mostly done in order to make the code cleaner:
struct myStruct blah;
vs.
myStruct blah;
I see some clarification is in order on this. C and C++ do not define types differently. C++ was originally nothing more than an additional set of includes on top of C.
The problem that virtually all C/C++ developers have today, is a) universities are no longer teaching the fundamentals, and b) people don't understand the difference between a definition and a declaration.
The only reason such declarations and definitions exist is so that the linker can calculate address offsets to the fields in the structure. This is why most people get away with code that is actually written incorrectly-- because the compiler is able to determine addressing. The problem arises when someone tries to do something advance, like a queue, or a linked list, or piggying-backing an O/S structure.
A declaration begins with 'struct', a definition begins with 'typedef'.
Further, a struct has a forward declaration label, and a defined label. Most people don't know this and use the forward declaration label as a define label.
Wrong:
struct myStruct
{
int field_1;
...
};
They've just used the forward declaration to label the structure-- so now the compiler is aware of it-- but it isn't an actual defined type. The compiler can calculate the addressing-- but this isn't how it was intended to be used, for reasons I will show momentarily.
People who use this form of declaration, must always put 'struct' in practicly every reference to it-- because it isn't an offical new type.
Instead, any structure that does not reference itself, should be declared and defined this way only:
typedef struct
{
field_1;
...
}myStruct;
Now it's an actual type, and when used you can use at as 'myStruct' without having to prepend it with the word 'struct'.
If you want a pointer variable to that structure, then include a secondary label:
typedef struct
{
field_1;
...
}myStruct,*myStructP;
Now you have a pointer variable to that structure, custom to it.
FORWARD DECLARATION--
Now, here's the fancy stuff, how the forward declaration works. If you want to create a type that refers to itself, like a linked list or queue element, you have to use a forward declaration. The compiler doesn't consider the structure defined until it gets to the semicolon at the very end, so it's just declared before that point.
typedef struct myStructElement
{
myStructElement* nextSE;
field_1;
...
}myStruct;
Now, the compiler knows that although it doesn't know what the whole type is yet, it can still reference it using the forward reference.
Please declare and typedef your structures correctly. There's actually a reason.
With the latter example you omit the struct keyword when using the structure. So everywhere in your code, you can write :
myStruct a;
instead of
struct myStruct a;
This save some typing, and might be more readable, but this is a matter of taste

Resources