Nested Structure Syntax - c

I have a quick question..is there any difference in these:
struct myinnerstruct
{
int x;
};
struct mystruct
{
struct myinnerstruct m;
int y;
};
AND THIS
struct mystruct
{
int x;
struct myinnerstruct
{
int y;
};
struct myinnerstruct m;
};
These both work as far as I can tell, but I'm wondering if there's a reason to pick one or the other. Thanks

The difference is that the second one is invalid.
The stuff between the { and } in a struct declaration is a sequence of member declarations. Your
struct myinnerstruct
{
int y;
};
is a type declaration; it doesn't declare a member of the enclosing struct, so it's illegal in that context.
What you can do is this:
struct mystruct
{
int x;
struct myinnerstruct
{
int y;
} m;
};
The declaration of m is a member declaration, so it's ok; it also declares the type struct myinnerstruct. But in my opinion, it's poor style. The type struct myinnerstruct remains visible after the declaration of struct mystruct is completed; see below for the explanation.
If you really want a struct within a struct like that, and you're not going to use struct myinnerstruct anywhere else, you could leave it without a tag:
struct mystruct
{
int x;
struct
{
int y;
} m;
};
But then you might as well declare y as a member of struct mystruct.
If you want struct innerstruct to be a named type, just declare it separately, as you did in your first example.
Here's the explanation of why struct innerstruct remains visible.
The C99 standard (large PDF), section 6.2.1 paragraph 2, says:
For each different entity that an identifier designates, the
identifier is visible (i.e., can be used) only within a region of
program text called its scope. Different entities designated by the
same identifier either have different scopes, or are in different name
spaces. There are four kinds of scopes: function, file, block, and
function prototype. (A function prototype is a declaration of a
function that declares the types of its parameters.)
The C90 and C11 standards have essentially the same wording.
The { braces } in a struct declaration do not define a block, nor do they define any of the other possible kinds of scope, so anything declared between the braces is not scoped to that region; it must be scoped to some surrounding context. It happens that the syntax lets you declare struct myinnerstruct inside another struct definition -- but only if it's part of a member definition. I think this is allowed only because the designers of the language didn't go to any extra effort to disallow it; it's just a side effect of other rules. You can do it, but I don't recommend it.

A reason to choose one or the other would be conventional expectations.
A structure declaration nested within another would not be expected to be reused elsewhere, even though it can be.
Also, there is a psychological clash by not putting things of the same level of abstraction side-by-side. It is perfectly legal to do it, but it makes understanding the code a little harder and maybe more irritating.

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

Declare data type structure [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

Convention for declaring structs in C [duplicate]

I have seen many programs consisting of structures like the one below
typedef struct
{
int i;
char k;
} elem;
elem user;
Why is it needed so often? Any specific reason or applicable area?
As Greg Hewgill said, the typedef means you no longer have to write struct all over the place. That not only saves keystrokes, it also can make the code cleaner since it provides a smidgen more abstraction.
Stuff like
typedef struct {
int x, y;
} Point;
Point point_new(int x, int y)
{
Point a;
a.x = x;
a.y = y;
return a;
}
becomes cleaner when you don't need to see the "struct" keyword all over the place, it looks more as if there really is a type called "Point" in your language. Which, after the typedef, is the case I guess.
Also note that while your example (and mine) omitted naming the struct itself, actually naming it is also useful for when you want to provide an opaque type. Then you'd have code like this in the header, for instance:
typedef struct Point Point;
Point * point_new(int x, int y);
and then provide the struct definition in the implementation file:
struct Point
{
int x, y;
};
Point * point_new(int x, int y)
{
Point *p;
if((p = malloc(sizeof *p)) != NULL)
{
p->x = x;
p->y = y;
}
return p;
}
In this latter case, you cannot return the Point by value, since its definition is hidden from users of the header file. This is a technique used widely in GTK+, for instance.
UPDATE Note that there are also highly-regarded C projects where this use of typedef to hide struct is considered a bad idea, the Linux kernel is probably the most well-known such project. See Chapter 5 of The Linux Kernel CodingStyle document for Linus' angry words. :) My point is that the "should" in the question is perhaps not set in stone, after all.
It's amazing how many people get this wrong. PLEASE don't typedef structs in C, it needlessly pollutes the global namespace which is typically very polluted already in large C programs.
Also, typedef'd structs without a tag name are a major cause of needless imposition of ordering relationships among header files.
Consider:
#ifndef FOO_H
#define FOO_H 1
#define FOO_DEF (0xDEADBABE)
struct bar; /* forward declaration, defined in bar.h*/
struct foo {
struct bar *bar;
};
#endif
With such a definition, not using typedefs, it is possible for a compiland unit to include foo.h to get at the FOO_DEF definition. If it doesn't attempt to dereference the 'bar' member of the foo struct then there will be no need to include the "bar.h" file.
Also, since the namespaces are different between the tag names and the member names, it is possible to write very readable code such as:
struct foo *foo;
printf("foo->bar = %p", foo->bar);
Since the namespaces are separate, there is no conflict in naming variables coincident with their struct tag name.
If I have to maintain your code, I will remove your typedef'd structs.
From an old article by Dan Saks (http://www.ddj.com/cpp/184403396?pgno=3):
The C language rules for naming
structs are a little eccentric, but
they're pretty harmless. However, when
extended to classes in C++, those same
rules open little cracks for bugs to
crawl through.
In C, the name s appearing in
struct s
{
...
};
is a tag. A tag name is not a type
name. Given the definition above,
declarations such as
s x; /* error in C */
s *p; /* error in C */
are errors in C. You must write them
as
struct s x; /* OK */
struct s *p; /* OK */
The names of unions and enumerations
are also tags rather than types.
In C, tags are distinct from all other
names (for functions, types,
variables, and enumeration constants).
C compilers maintain tags in a symbol
table that's conceptually if not
physically separate from the table
that holds all other names. Thus, it
is possible for a C program to have
both a tag and an another name with
the same spelling in the same scope.
For example,
struct s s;
is a valid declaration which declares
variable s of type struct s. It may
not be good practice, but C compilers
must accept it. I have never seen a
rationale for why C was designed this
way. I have always thought it was a
mistake, but there it is.
Many programmers (including yours
truly) prefer to think of struct names
as type names, so they define an alias
for the tag using a typedef. For
example, defining
struct s
{
...
};
typedef struct s S;
lets you use S in place of struct s,
as in
S x;
S *p;
A program cannot use S as the name of
both a type and a variable (or
function or enumeration constant):
S S; // error
This is good.
The tag name in a struct, union, or
enum definition is optional. Many
programmers fold the struct definition
into the typedef and dispense with the
tag altogether, as in:
typedef struct
{
...
} S;
The linked article also has a discussion about how the C++ behavior of not requireing a typedef can cause subtle name hiding problems. To prevent these problems, it's a good idea to typedef your classes and structs in C++, too, even though at first glance it appears to be unnecessary. In C++, with the typedef the name hiding become an error that the compiler tells you about rather than a hidden source of potential problems.
Using a typedef avoids having to write struct every time you declare a variable of that type:
struct elem
{
int i;
char k;
};
elem user; // compile error!
struct elem user; // this is correct
One other good reason to always typedef enums and structs results from this problem:
enum EnumDef
{
FIRST_ITEM,
SECOND_ITEM
};
struct StructDef
{
enum EnuumDef MyEnum;
unsigned int MyVar;
} MyStruct;
Notice the typo in EnumDef in the struct (EnuumDef)? This compiles without error (or warning) and is (depending on the literal interpretation of the C Standard) correct. The problem is that I just created an new (empty) enumeration definition within my struct. I am not (as intended) using the previous definition EnumDef.
With a typdef similar kind of typos would have resulted in a compiler errors for using an unknown type:
typedef
{
FIRST_ITEM,
SECOND_ITEM
} EnumDef;
typedef struct
{
EnuumDef MyEnum; /* compiler error (unknown type) */
unsigned int MyVar;
} StructDef;
StrructDef MyStruct; /* compiler error (unknown type) */
I would advocate ALWAYS typedef'ing structs and enumerations.
Not only to save some typing (no pun intended ;)), but because it is safer.
Linux kernel coding style Chapter 5 gives great pros and cons (mostly cons) of using typedef.
Please don't use things like "vps_t".
It's a mistake to use typedef for structures and pointers. When you see a
vps_t a;
in the source, what does it mean?
In contrast, if it says
struct virtual_container *a;
you can actually tell what "a" is.
Lots of people think that typedefs "help readability". Not so. They are useful only for:
(a) totally opaque objects (where the typedef is actively used to hide what the object is).
Example: "pte_t" etc. opaque objects that you can only access using the proper accessor functions.
NOTE! Opaqueness and "accessor functions" are not good in themselves. The reason we have them for things like pte_t etc. is that there really is absolutely zero portably accessible information there.
(b) Clear integer types, where the abstraction helps avoid confusion whether it is "int" or "long".
u8/u16/u32 are perfectly fine typedefs, although they fit into category (d) better than here.
NOTE! Again - there needs to be a reason for this. If something is "unsigned long", then there's no reason to do
typedef unsigned long myflags_t;
but if there is a clear reason for why it under certain circumstances might be an "unsigned int" and under other configurations might be "unsigned long", then by all means go ahead and use a typedef.
(c) when you use sparse to literally create a new type for type-checking.
(d) New types which are identical to standard C99 types, in certain exceptional circumstances.
Although it would only take a short amount of time for the eyes and brain to become accustomed to the standard types like 'uint32_t', some people object to their use anyway.
Therefore, the Linux-specific 'u8/u16/u32/u64' types and their signed equivalents which are identical to standard types are permitted -- although they are not mandatory in new code of your own.
When editing existing code which already uses one or the other set of types, you should conform to the existing choices in that code.
(e) Types safe for use in userspace.
In certain structures which are visible to userspace, we cannot require C99 types and cannot use the 'u32' form above. Thus, we use __u32 and similar types in all structures which are shared with userspace.
Maybe there are other cases too, but the rule should basically be to NEVER EVER use a typedef unless you can clearly match one of those rules.
In general, a pointer, or a struct that has elements that can reasonably be directly accessed should never be a typedef.
It turns out that there are pros and cons. A useful source of information is the seminal book "Expert C Programming" (Chapter 3). Briefly, in C you have multiple namespaces: tags, types, member names and identifiers. typedef introduces an alias for a type and locates it in the tag namespace. Namely,
typedef struct Tag{
...members...
}Type;
defines two things. 1) Tag in the tag namespace and 2) Type in the type namespace. So you can do both Type myType and struct Tag myTagType. Declarations like struct Type myType or Tag myTagType are illegal. In addition, in a declaration like this:
typedef Type *Type_ptr;
we define a pointer to our Type. So if we declare:
Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;
then var1,var2 and myTagType1 are pointers to Type but myTagType2 not.
In the above-mentioned book, it mentions that typedefing structs are not very useful as it only saves the programmer from writing the word struct. However, I have an objection, like many other C programmers. Although it sometimes turns to obfuscate some names (that's why it is not advisable in large code bases like the kernel) when you want to implement polymorphism in C it helps a lot look here for details. Example:
typedef struct MyWriter_t{
MyPipe super;
MyQueue relative;
uint32_t flags;
...
}MyWriter;
you can do:
void my_writer_func(MyPipe *s)
{
MyWriter *self = (MyWriter *) s;
uint32_t myFlags = self->flags;
...
}
So you can access an outer member (flags) by the inner struct (MyPipe) through casting. For me it is less confusing to cast the whole type than doing (struct MyWriter_ *) s; every time you want to perform such functionality. In these cases brief referencing is a big deal especially if you heavily employ the technique in your code.
Finally, the last aspect with typedefed types is the inability to extend them, in contrast to macros. If for example, you have:
#define X char[10] or
typedef char Y[10]
you can then declare
unsigned X x; but not
unsigned Y y;
We do not really care for this for structs because it does not apply to storage specifiers (volatile and const).
I don't think forward declarations are even possible with typedef. Use of struct, enum, and union allow for forwarding declarations when dependencies (knows about) is bidirectional.
Style:
Use of typedef in C++ makes quite a bit of sense. It can almost be necessary when dealing with templates that require multiple and/or variable parameters. The typedef helps keep the naming straight.
Not so in the C programming language. The use of typedef most often serves no purpose but to obfuscate the data structure usage. Since only { struct (6), enum (4), union (5) } number of keystrokes are used to declare a data type there is almost no use for the aliasing of the struct. Is that data type a union or a struct? Using the straightforward non-typdefed declaration lets you know right away what type it is.
Notice how Linux is written with strict avoidance of this aliasing nonsense typedef brings. The result is a minimalist and clean style.
Let's start with the basics and work our way up.
Here is an example of Structure definition:
struct point
{
int x, y;
};
Here the name point is optional.
A Structure can be declared during its definition or after.
Declaring during definition
struct point
{
int x, y;
} first_point, second_point;
Declaring after definition
struct point
{
int x, y;
};
struct point first_point, second_point;
Now, carefully note the last case above; you need to write struct point to declare Structures of that type if you decide to create that type at a later point in your code.
Enter typedef. If you intend to create new Structure ( Structure is a custom data-type) at a later time in your program using the same blueprint, using typedef during its definition might be a good idea since you can save some typing moving forward.
typedef struct point
{
int x, y;
} Points;
Points first_point, second_point;
A word of caution while naming your custom type
Nothing prevents you from using _t suffix at the end of your custom type name but POSIX standard reserves the use of suffix _t to denote standard library type names.
The name you (optionally) give the struct is called the tag name and, as has been noted, is not a type in itself. To get to the type requires the struct prefix.
GTK+ aside, I'm not sure the tagname is used anything like as commonly as a typedef to the struct type, so in C++ that is recognised and you can omit the struct keyword and use the tagname as the type name too:
struct MyStruct
{
int i;
};
// The following is legal in C++:
MyStruct obj;
obj.i = 7;
typedef will not provide a co-dependent set of data structures. This you cannot do with typdef:
struct bar;
struct foo;
struct foo {
struct bar *b;
};
struct bar {
struct foo *f;
};
Of course you can always add:
typedef struct foo foo_t;
typedef struct bar bar_t;
What exactly is the point of that?
A>
a typdef aids in the meaning and documentation of a program by allowing creation of more meaningful synonyms for data types. In addition, they help parameterize a program against portability problems (K&R, pg147, C prog lang).
B>
a structure defines a type. Structs allows convenient grouping of a collection of vars for convenience of handling (K&R, pg127, C prog lang.) as a single unit
C>
typedef'ing a struct is explained in A above.
D> To me, structs are custom types or containers or collections or namespaces or complex types, whereas a typdef is just a means to create more nicknames.
In 'C' programming language the keyword 'typedef' is used to declare a new name for some object(struct, array, function..enum type). For example, I will use a 'struct-s'.
In 'C' we often declare a 'struct' outside of the 'main' function. For example:
struct complex{ int real_part, img_part }COMPLEX;
main(){
struct KOMPLEKS number; // number type is now a struct type
number.real_part = 3;
number.img_part = -1;
printf("Number: %d.%d i \n",number.real_part, number.img_part);
}
Each time I decide to use a struct type I will need this keyword 'struct 'something' 'name'.'typedef' will simply rename that type and I can use that new name in my program every time I want. So our code will be:
typedef struct complex{int real_part, img_part; }COMPLEX;
//now COMPLEX is the new name for this structure and if I want to use it without
// a keyword like in the first example 'struct complex number'.
main(){
COMPLEX number; // number is now the same type as in the first example
number.real_part = 1;
number.img)part = 5;
printf("%d %d \n", number.real_part, number.img_part);
}
If you have some local object(struct, array, valuable) that will be used in your entire program you can simply give it a name using a 'typedef'.
Turns out in C99 typedef is required. It is outdated, but a lot of tools (ala HackRank) use c99 as its pure C implementation. And typedef is required there.
I'm not saying they should change (maybe have two C options) if the requirement changed, those of us studing for interviews on the site would be SOL.
At all, in C language, struct/union/enum are macro instruction processed by the C language preprocessor (do not mistake with the preprocessor that treat "#include" and other)
so :
struct a
{
int i;
};
struct b
{
struct a;
int i;
int j;
};
struct b is expended as something like this :
struct b
{
struct a
{
int i;
};
int i;
int j;
}
and so, at compile time it evolve on stack as something like:
b:
int ai
int i
int j
that also why it's dificult to have selfreferent structs, C preprocessor round in a déclaration loop that can't terminate.
typedef are type specifier, that means only C compiler process it and it can do like he want for optimise assembler code implementation. It also dont expend member of type par stupidly like préprocessor do with structs but use more complex reference construction algorithm, so construction like :
typedef struct a A; //anticipated declaration for member declaration
typedef struct a //Implemented declaration
{
A* b; // member declaration
}A;
is permited and fully functional. This implementation give also access to compilator type conversion and remove some bugging effects when execution thread leave the application field of initialisation functions.
This mean that in C typedefs are more near as C++ class than lonely structs.

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

Why should we typedef a struct so often in C?

I have seen many programs consisting of structures like the one below
typedef struct
{
int i;
char k;
} elem;
elem user;
Why is it needed so often? Any specific reason or applicable area?
As Greg Hewgill said, the typedef means you no longer have to write struct all over the place. That not only saves keystrokes, it also can make the code cleaner since it provides a smidgen more abstraction.
Stuff like
typedef struct {
int x, y;
} Point;
Point point_new(int x, int y)
{
Point a;
a.x = x;
a.y = y;
return a;
}
becomes cleaner when you don't need to see the "struct" keyword all over the place, it looks more as if there really is a type called "Point" in your language. Which, after the typedef, is the case I guess.
Also note that while your example (and mine) omitted naming the struct itself, actually naming it is also useful for when you want to provide an opaque type. Then you'd have code like this in the header, for instance:
typedef struct Point Point;
Point * point_new(int x, int y);
and then provide the struct definition in the implementation file:
struct Point
{
int x, y;
};
Point * point_new(int x, int y)
{
Point *p;
if((p = malloc(sizeof *p)) != NULL)
{
p->x = x;
p->y = y;
}
return p;
}
In this latter case, you cannot return the Point by value, since its definition is hidden from users of the header file. This is a technique used widely in GTK+, for instance.
UPDATE Note that there are also highly-regarded C projects where this use of typedef to hide struct is considered a bad idea, the Linux kernel is probably the most well-known such project. See Chapter 5 of The Linux Kernel CodingStyle document for Linus' angry words. :) My point is that the "should" in the question is perhaps not set in stone, after all.
It's amazing how many people get this wrong. PLEASE don't typedef structs in C, it needlessly pollutes the global namespace which is typically very polluted already in large C programs.
Also, typedef'd structs without a tag name are a major cause of needless imposition of ordering relationships among header files.
Consider:
#ifndef FOO_H
#define FOO_H 1
#define FOO_DEF (0xDEADBABE)
struct bar; /* forward declaration, defined in bar.h*/
struct foo {
struct bar *bar;
};
#endif
With such a definition, not using typedefs, it is possible for a compiland unit to include foo.h to get at the FOO_DEF definition. If it doesn't attempt to dereference the 'bar' member of the foo struct then there will be no need to include the "bar.h" file.
Also, since the namespaces are different between the tag names and the member names, it is possible to write very readable code such as:
struct foo *foo;
printf("foo->bar = %p", foo->bar);
Since the namespaces are separate, there is no conflict in naming variables coincident with their struct tag name.
If I have to maintain your code, I will remove your typedef'd structs.
From an old article by Dan Saks (http://www.ddj.com/cpp/184403396?pgno=3):
The C language rules for naming
structs are a little eccentric, but
they're pretty harmless. However, when
extended to classes in C++, those same
rules open little cracks for bugs to
crawl through.
In C, the name s appearing in
struct s
{
...
};
is a tag. A tag name is not a type
name. Given the definition above,
declarations such as
s x; /* error in C */
s *p; /* error in C */
are errors in C. You must write them
as
struct s x; /* OK */
struct s *p; /* OK */
The names of unions and enumerations
are also tags rather than types.
In C, tags are distinct from all other
names (for functions, types,
variables, and enumeration constants).
C compilers maintain tags in a symbol
table that's conceptually if not
physically separate from the table
that holds all other names. Thus, it
is possible for a C program to have
both a tag and an another name with
the same spelling in the same scope.
For example,
struct s s;
is a valid declaration which declares
variable s of type struct s. It may
not be good practice, but C compilers
must accept it. I have never seen a
rationale for why C was designed this
way. I have always thought it was a
mistake, but there it is.
Many programmers (including yours
truly) prefer to think of struct names
as type names, so they define an alias
for the tag using a typedef. For
example, defining
struct s
{
...
};
typedef struct s S;
lets you use S in place of struct s,
as in
S x;
S *p;
A program cannot use S as the name of
both a type and a variable (or
function or enumeration constant):
S S; // error
This is good.
The tag name in a struct, union, or
enum definition is optional. Many
programmers fold the struct definition
into the typedef and dispense with the
tag altogether, as in:
typedef struct
{
...
} S;
The linked article also has a discussion about how the C++ behavior of not requireing a typedef can cause subtle name hiding problems. To prevent these problems, it's a good idea to typedef your classes and structs in C++, too, even though at first glance it appears to be unnecessary. In C++, with the typedef the name hiding become an error that the compiler tells you about rather than a hidden source of potential problems.
Using a typedef avoids having to write struct every time you declare a variable of that type:
struct elem
{
int i;
char k;
};
elem user; // compile error!
struct elem user; // this is correct
One other good reason to always typedef enums and structs results from this problem:
enum EnumDef
{
FIRST_ITEM,
SECOND_ITEM
};
struct StructDef
{
enum EnuumDef MyEnum;
unsigned int MyVar;
} MyStruct;
Notice the typo in EnumDef in the struct (EnuumDef)? This compiles without error (or warning) and is (depending on the literal interpretation of the C Standard) correct. The problem is that I just created an new (empty) enumeration definition within my struct. I am not (as intended) using the previous definition EnumDef.
With a typdef similar kind of typos would have resulted in a compiler errors for using an unknown type:
typedef
{
FIRST_ITEM,
SECOND_ITEM
} EnumDef;
typedef struct
{
EnuumDef MyEnum; /* compiler error (unknown type) */
unsigned int MyVar;
} StructDef;
StrructDef MyStruct; /* compiler error (unknown type) */
I would advocate ALWAYS typedef'ing structs and enumerations.
Not only to save some typing (no pun intended ;)), but because it is safer.
Linux kernel coding style Chapter 5 gives great pros and cons (mostly cons) of using typedef.
Please don't use things like "vps_t".
It's a mistake to use typedef for structures and pointers. When you see a
vps_t a;
in the source, what does it mean?
In contrast, if it says
struct virtual_container *a;
you can actually tell what "a" is.
Lots of people think that typedefs "help readability". Not so. They are useful only for:
(a) totally opaque objects (where the typedef is actively used to hide what the object is).
Example: "pte_t" etc. opaque objects that you can only access using the proper accessor functions.
NOTE! Opaqueness and "accessor functions" are not good in themselves. The reason we have them for things like pte_t etc. is that there really is absolutely zero portably accessible information there.
(b) Clear integer types, where the abstraction helps avoid confusion whether it is "int" or "long".
u8/u16/u32 are perfectly fine typedefs, although they fit into category (d) better than here.
NOTE! Again - there needs to be a reason for this. If something is "unsigned long", then there's no reason to do
typedef unsigned long myflags_t;
but if there is a clear reason for why it under certain circumstances might be an "unsigned int" and under other configurations might be "unsigned long", then by all means go ahead and use a typedef.
(c) when you use sparse to literally create a new type for type-checking.
(d) New types which are identical to standard C99 types, in certain exceptional circumstances.
Although it would only take a short amount of time for the eyes and brain to become accustomed to the standard types like 'uint32_t', some people object to their use anyway.
Therefore, the Linux-specific 'u8/u16/u32/u64' types and their signed equivalents which are identical to standard types are permitted -- although they are not mandatory in new code of your own.
When editing existing code which already uses one or the other set of types, you should conform to the existing choices in that code.
(e) Types safe for use in userspace.
In certain structures which are visible to userspace, we cannot require C99 types and cannot use the 'u32' form above. Thus, we use __u32 and similar types in all structures which are shared with userspace.
Maybe there are other cases too, but the rule should basically be to NEVER EVER use a typedef unless you can clearly match one of those rules.
In general, a pointer, or a struct that has elements that can reasonably be directly accessed should never be a typedef.
It turns out that there are pros and cons. A useful source of information is the seminal book "Expert C Programming" (Chapter 3). Briefly, in C you have multiple namespaces: tags, types, member names and identifiers. typedef introduces an alias for a type and locates it in the tag namespace. Namely,
typedef struct Tag{
...members...
}Type;
defines two things. 1) Tag in the tag namespace and 2) Type in the type namespace. So you can do both Type myType and struct Tag myTagType. Declarations like struct Type myType or Tag myTagType are illegal. In addition, in a declaration like this:
typedef Type *Type_ptr;
we define a pointer to our Type. So if we declare:
Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;
then var1,var2 and myTagType1 are pointers to Type but myTagType2 not.
In the above-mentioned book, it mentions that typedefing structs are not very useful as it only saves the programmer from writing the word struct. However, I have an objection, like many other C programmers. Although it sometimes turns to obfuscate some names (that's why it is not advisable in large code bases like the kernel) when you want to implement polymorphism in C it helps a lot look here for details. Example:
typedef struct MyWriter_t{
MyPipe super;
MyQueue relative;
uint32_t flags;
...
}MyWriter;
you can do:
void my_writer_func(MyPipe *s)
{
MyWriter *self = (MyWriter *) s;
uint32_t myFlags = self->flags;
...
}
So you can access an outer member (flags) by the inner struct (MyPipe) through casting. For me it is less confusing to cast the whole type than doing (struct MyWriter_ *) s; every time you want to perform such functionality. In these cases brief referencing is a big deal especially if you heavily employ the technique in your code.
Finally, the last aspect with typedefed types is the inability to extend them, in contrast to macros. If for example, you have:
#define X char[10] or
typedef char Y[10]
you can then declare
unsigned X x; but not
unsigned Y y;
We do not really care for this for structs because it does not apply to storage specifiers (volatile and const).
I don't think forward declarations are even possible with typedef. Use of struct, enum, and union allow for forwarding declarations when dependencies (knows about) is bidirectional.
Style:
Use of typedef in C++ makes quite a bit of sense. It can almost be necessary when dealing with templates that require multiple and/or variable parameters. The typedef helps keep the naming straight.
Not so in the C programming language. The use of typedef most often serves no purpose but to obfuscate the data structure usage. Since only { struct (6), enum (4), union (5) } number of keystrokes are used to declare a data type there is almost no use for the aliasing of the struct. Is that data type a union or a struct? Using the straightforward non-typdefed declaration lets you know right away what type it is.
Notice how Linux is written with strict avoidance of this aliasing nonsense typedef brings. The result is a minimalist and clean style.
Let's start with the basics and work our way up.
Here is an example of Structure definition:
struct point
{
int x, y;
};
Here the name point is optional.
A Structure can be declared during its definition or after.
Declaring during definition
struct point
{
int x, y;
} first_point, second_point;
Declaring after definition
struct point
{
int x, y;
};
struct point first_point, second_point;
Now, carefully note the last case above; you need to write struct point to declare Structures of that type if you decide to create that type at a later point in your code.
Enter typedef. If you intend to create new Structure ( Structure is a custom data-type) at a later time in your program using the same blueprint, using typedef during its definition might be a good idea since you can save some typing moving forward.
typedef struct point
{
int x, y;
} Points;
Points first_point, second_point;
A word of caution while naming your custom type
Nothing prevents you from using _t suffix at the end of your custom type name but POSIX standard reserves the use of suffix _t to denote standard library type names.
The name you (optionally) give the struct is called the tag name and, as has been noted, is not a type in itself. To get to the type requires the struct prefix.
GTK+ aside, I'm not sure the tagname is used anything like as commonly as a typedef to the struct type, so in C++ that is recognised and you can omit the struct keyword and use the tagname as the type name too:
struct MyStruct
{
int i;
};
// The following is legal in C++:
MyStruct obj;
obj.i = 7;
typedef will not provide a co-dependent set of data structures. This you cannot do with typdef:
struct bar;
struct foo;
struct foo {
struct bar *b;
};
struct bar {
struct foo *f;
};
Of course you can always add:
typedef struct foo foo_t;
typedef struct bar bar_t;
What exactly is the point of that?
A>
a typdef aids in the meaning and documentation of a program by allowing creation of more meaningful synonyms for data types. In addition, they help parameterize a program against portability problems (K&R, pg147, C prog lang).
B>
a structure defines a type. Structs allows convenient grouping of a collection of vars for convenience of handling (K&R, pg127, C prog lang.) as a single unit
C>
typedef'ing a struct is explained in A above.
D> To me, structs are custom types or containers or collections or namespaces or complex types, whereas a typdef is just a means to create more nicknames.
In 'C' programming language the keyword 'typedef' is used to declare a new name for some object(struct, array, function..enum type). For example, I will use a 'struct-s'.
In 'C' we often declare a 'struct' outside of the 'main' function. For example:
struct complex{ int real_part, img_part }COMPLEX;
main(){
struct KOMPLEKS number; // number type is now a struct type
number.real_part = 3;
number.img_part = -1;
printf("Number: %d.%d i \n",number.real_part, number.img_part);
}
Each time I decide to use a struct type I will need this keyword 'struct 'something' 'name'.'typedef' will simply rename that type and I can use that new name in my program every time I want. So our code will be:
typedef struct complex{int real_part, img_part; }COMPLEX;
//now COMPLEX is the new name for this structure and if I want to use it without
// a keyword like in the first example 'struct complex number'.
main(){
COMPLEX number; // number is now the same type as in the first example
number.real_part = 1;
number.img)part = 5;
printf("%d %d \n", number.real_part, number.img_part);
}
If you have some local object(struct, array, valuable) that will be used in your entire program you can simply give it a name using a 'typedef'.
Turns out in C99 typedef is required. It is outdated, but a lot of tools (ala HackRank) use c99 as its pure C implementation. And typedef is required there.
I'm not saying they should change (maybe have two C options) if the requirement changed, those of us studing for interviews on the site would be SOL.
At all, in C language, struct/union/enum are macro instruction processed by the C language preprocessor (do not mistake with the preprocessor that treat "#include" and other)
so :
struct a
{
int i;
};
struct b
{
struct a;
int i;
int j;
};
struct b is expended as something like this :
struct b
{
struct a
{
int i;
};
int i;
int j;
}
and so, at compile time it evolve on stack as something like:
b:
int ai
int i
int j
that also why it's dificult to have selfreferent structs, C preprocessor round in a déclaration loop that can't terminate.
typedef are type specifier, that means only C compiler process it and it can do like he want for optimise assembler code implementation. It also dont expend member of type par stupidly like préprocessor do with structs but use more complex reference construction algorithm, so construction like :
typedef struct a A; //anticipated declaration for member declaration
typedef struct a //Implemented declaration
{
A* b; // member declaration
}A;
is permited and fully functional. This implementation give also access to compilator type conversion and remove some bugging effects when execution thread leave the application field of initialisation functions.
This mean that in C typedefs are more near as C++ class than lonely structs.

Resources