What Is the Meaning of 'Struct X Typedef' VS. 'Typedef Struct X'

typedef struct vs struct definitions

The common idiom is using both:

typedef struct S { 
int x;
} S;

They are different definitions. To make the discussion clearer I will split the sentence:

struct S { 
int x;
};

typedef struct S S;

In the first line you are defining the identifier S within the struct name space (not in the C++ sense). You can use it and define variables or function arguments of the newly defined type by defining the type of the argument as struct S:

void f( struct S argument ); // struct is required here

The second line adds a type alias S in the global name space and thus allows you to just write:

void f( S argument ); // struct keyword no longer needed

Note that since both identifier name spaces are different, defining S both in the structs and global spaces is not an error, as it is not redefining the same identifier, but rather creating a different identifier in a different place.

To make the difference clearer:

typedef struct S { 
int x;
} T;

void S() { } // correct

//void T() {} // error: symbol T already defined as an alias to 'struct S'

You can define a function with the same name of the struct as the identifiers are kept in different spaces, but you cannot define a function with the same name as a typedef as those identifiers collide.

In C++, it is slightly different as the rules to locate a symbol have changed subtly. C++ still keeps the two different identifier spaces, but unlike in C, when you only define the symbol within the class identifier space, you are not required to provide the struct/class keyword:

 // C++
struct S {
int x;
}; // S defined as a class

void f( S a ); // correct: struct is optional

What changes are the search rules, not where the identifiers are defined. The compiler will search the global identifier table and after S has not been found it will search for S within the class identifiers.

The code presented before behaves in the same way:

typedef struct S { 
int x;
} T;

void S() {} // correct [*]

//void T() {} // error: symbol T already defined as an alias to 'struct S'

After the definition of the S function in the second line, the struct S cannot be resolved automatically by the compiler, and to create an object or define an argument of that type you must fall back to including the struct keyword:

// previous code here...
int main() {
S();
struct S s;
}

What's the difference between `typedef struct X { }` and `typedef struct { } X`?

The first declaration:

typedef struct square {
// Some fields
};

defines a type named struct square. The typedef keyword is redundant (thanks to HolyBlackCat for pointing that out). It's equivalent to:

struct square {
//Some fields
};

(The fact that you can use the typedef keyword in a declaration without defining a type name is a glitch in C's syntax.)

This first declaration probably should have been:

typedef struct square {
// Some fields
} square;

The second declaration:

typedef struct {
// Some fields
} square;

defines an anonymous struct type and then gives it the alias square.

Remember that typedef by itself doesn't define a new type, only a new name for an existing type. In this case the typedef and the (anonymous) struct definition happen to be combined into a single declaration.

What is the meaning of `struct X typedef` vs. `typedef struct X`?

The fact that both typedef <type> <alias> and <type> typedef <alias> are valid simply comes from the language grammar definition.

typedef is classified as a storage-class specfifier (just like static, auto), and the type itself is known as the type-specifier. From the syntax definitions in section 6.7 of the standard, you'll see that these are free to be interchanged:

declaration:
declaration-specifiers init-declarator-list ;

declaration-specifiers:
storage-class-specifier declaration-specifiers
type-specifier declaration-specifiers
type-qualifier declaration-specifiers
function-specifier declaration-specifiers

init-declarator-list:
init-declarator
init-declarator-list , init-declarator

init-declarator:
declarator
declarator = initializer

(Note, of course, that this is equally true for structs and for non-structs, meaning that double typedef trouble; is also valid.)

Difference between 'struct' and 'typedef struct' in C++?

In C++, there is only a subtle difference. It's a holdover from C, in which it makes a difference.

The C language standard (C89 §3.1.2.3, C99 §6.2.3, and C11 §6.2.3) mandates separate namespaces for different categories of identifiers, including tag identifiers (for struct/union/enum) and ordinary identifiers (for typedef and other identifiers).

If you just said:

struct Foo { ... };
Foo x;

you would get a compiler error, because Foo is only defined in the tag namespace.

You'd have to declare it as:

struct Foo x;

Any time you want to refer to a Foo, you'd always have to call it a struct Foo. This gets annoying fast, so you can add a typedef:

struct Foo { ... };
typedef struct Foo Foo;

Now struct Foo (in the tag namespace) and just plain Foo (in the ordinary identifier namespace) both refer to the same thing, and you can freely declare objects of type Foo without the struct keyword.


The construct:

typedef struct Foo { ... } Foo;

is just an abbreviation for the declaration and typedef.


Finally,

typedef struct { ... } Foo;

declares an anonymous structure and creates a typedef for it. Thus, with this construct, it doesn't have a name in the tag namespace, only a name in the typedef namespace. This means it also cannot be forward-declared. If you want to make a forward declaration, you have to give it a name in the tag namespace.


In C++, all struct/union/enum/class declarations act like they are implicitly typedef'ed, as long as the name is not hidden by another declaration with the same name. See Michael Burr's answer for the full details.

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

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:

  1. definition of struct type,
  2. definition and declaration of struct variable, and
  3. 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.

Why should we typedef a struct so often in C?

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.

Typedef struct declared as two types: typedef struct x { .. } X, *XPointer

The Linux kernel coding style says to avoid these kinds of typedefs:

Chapter 5: Typedefs

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.

Difference between these 2 declarations of structures in C

This typedef declaration

typedef struct sala local, *local;
struct sala {
int id;
int capacidade;
int liga[3];
};

is invalid because the name local is declared twice with different meanings: the first one as an alias for the type struct sala and the second one as an alias for the type struct sala *.

This is the difference between the first and the second typedef declarations.:)

As for the placement of typedef declaration then it may be placed either before a corresponding structure definition. together with structure definition or after structure definition.

For example

typedef struct A A;
struct A
{
int x;
};

or

typedef struct A
{
int x;
} A;

or

struct A
{
int x;
};

typedef struct A A;

An essence difference between these declarations is that if you want to refer to the defined structure inside its definition then in the second and third cases you have to use the type name struct A because the typedef name A was not yet declared.

For example

typedef struct Node Node;
struct Node
{
int x;
Node *next;
};

but for example

typedef struct Node
{
int x;
struct Node *next;
} Node;

What is the difference between these two structure declarations?

With the first you can use either the type-alias COMPLEX or struct complex.

With the second you have an anonymous structure which can only be used with the type-alias COMPLEX.

With that said, in C++ any structure name is also a type-name and can be used as a type directly:

struct complex { ... };
complex c1;

Why is `typedef struct x x` allowed?

This works because C has multiple name spaces:

  • labels (disambiguated by goto or trailing :);
  • tag names for struct, enum, and union (disambiguated by the struct, union, or enum keywords):
  • names for struct and union members (disambiguated by a leading . or ->, each struct or union type acts as its own namespace, so different struct and union types can use the same member names);
  • all other identifiers (variable and function names, typedef names, enumeration constants, etc.).

So you can use the same name as a label, a tag name, a member name, and a regular identifier all in the same code, and the compiler is able to distinguish between them:

struct x { int x; }; // tag name, member name

void foo( struct x x ) // tag name, all other identifiers
{
if ( x.x ) // all other identifiers, member name
goto x; // label name

// do something here

x: printf( "At label x\n" ); // label name
}


Related Topics



Leave a reply



Submit