39

I've seen C structs declared several different ways before. Why is that and what, if anything, does each do different?

For example:

struct foo {
  short a;
  int b;
  float c;
};

typedef struct {
  short d;
  int e;
  float f;
} bar;

typedef struct _baz {
  short a;
  int b;
  float c;
} baz;

int main (int argc, char const *argv[])
{
  struct foo a;
  bar b;
  baz c;

  return 0;
}
Mark Sands
  • 1,509
  • 1
  • 14
  • 15
  • This doesn't answer your question for C, but I believe they are all correct for C++, though the first one is preferred. This may have also changed between different versions of C, but I'll let someone else speak to that, since I'm no expert on the history of C/C++. – Merlyn Morgan-Graham Jan 15 '11 at 08:10
  • 2
    C++ is different: when you write `struct Foo { };` or `class Foo { };` there, you get `Foo` for free without a `typedef`. – Fred Foo Jan 15 '11 at 08:18
  • They all will still work, though, even though they might do slightly different things (like pollute your namespace w/ extra tags). – Merlyn Morgan-Graham Jan 15 '11 at 08:20
  • @Merlyn - Not exactly. `class X` lets you declare `X x;`, but `X` is still in the `class` / `struct` tag namespace, which allows people to try nasty things like `class singleton { ... } singleton;` – Chris Lutz Jan 15 '11 at 08:30
  • 3
    Note that using leading underscores in your struct tag names is almost surely incorrect. It can break things and serves no purpose. Don't do it. – R.. GitHub STOP HELPING ICE Jan 15 '11 at 13:14

4 Answers4

34

Well, the obvious difference is demonstrated in your main:

struct foo a;
bar b;
baz c;

The first declaration is of an un-typedefed struct and needs the struct keyword to use. The second is of a typedefed anonymous struct, and so we use the typedef name. The third combines both the first and the second: your example uses baz (which is conveniently short) but could just as easily use struct _baz to the same effect.

Update: larsmans' answer mentions a more common case where you have to use at least struct x { } to make a linked list. The second case wouldn't be possible here (unless you abandon sanity and use a void * instead) because the struct is anonymous, and the typedef doesn't happen until the struct is defined, giving you no way to make a (type-safe) pointer to the struct type itself. The first version works fine for this use, but the third is generally preferred in my experience. Give him some rep for that.

A more subtle difference is in namespace placement. In C, struct tags are placed in a separate namespace from other names, but typedef names aren't. So the following is legal:

struct test {
  // contents
};

struct test *test() {
  // contents
}

But the following is not, because it would be ambiguous what the name test is:

typedef struct {
  // contents
} test;

test *test() {
  // contents
}

typedef makes the name shorter (always a plus), but it puts it in the same namespace as your variables and functions. Usually this isn't an issue, but it is a subtle difference beyond the simple shortening.

Community
  • 1
  • 1
Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
  • Would using the same name for both the tag and the typedef be illegal? Or not a good idea? Or is that perfectly fine? For instance: typedef struct mystruct{ } mystruct; – SeanRamey Jan 23 '18 at 21:23
  • No it's not illegal since they sit in different namespaces. Read https://stackoverflow.com/a/1675446/6214440 for a good explanation. Also note that in C11 you can define anonymous structs: `typedef struct { ... } Foo` –  Oct 11 '19 at 07:13
31

It's largely a matter of personal preference. I like to give new types a name starting with a capital letter and omit the struct, so I usually write typedef struct { ... } Foo. That means I cannot then write struct Foo.

The exception is when a struct contains a pointer to its own type, e.g.

typedef struct Node {
    // ...
    struct Node *next;
} Node;

In this case you need to also declare the struct Node type, since the typedef is not in scope within the struct definition. Note that both names may be the same (I'm not sure where the underscore convention originated, but I guess older C compilers couldn't handle typedef struct X X;).

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
9

The confusion comes about because some of the declarations are in fact declaring up to three C constructs. You need to keep in mind the difference between:

  1. A typedef declaration,
  2. A struct definition, and
  3. A struct declaration.

They are all very different C constructs. They all do different things; but you can combine them into the one compound construct, if you want to.

Let's look at each declaration in turn.


struct foo {
  short a;
  int b;
  float c;
};

Here we are using the most basic struct definition syntax. We are defining a C type and give it the name foo in the tag namespace. It can later be used to declare variables of that type using the following syntax:

struct foo myFoo;  // Declare a struct variable of type foo.

This next declaration gives the type another name (alias) in the global namespace. Let's break it down into its components using the previous basic declaration.

typedef struct foo bar;   // Declare bar as a variable type, the alias of foo.

bar myBar;         // No need for the "struct" keyword

Now just replace "foo" with the the struct's definition and voila!

typedef struct {
  short d;    
  int e;
  float f;
} bar;

typedef struct _baz {
  short a;
  int b;
  float c;
} baz;

The above syntax is equivalent to the following sequence of declarations.

struct _baz {
  short a;
  int b;
  float c;
};

typedef struct _baz baz;  // Declare baz as an alias for _baz.

baz myBaz;               // Is the same as: struct _baz myBaz;
Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Mike T
  • 91
  • 1
  • 1
9

All your uses are syntactically correct. I prefer the following usage

 /* forward declare all structs and typedefs */
typedef struct foo foo;
.
.
/* declare the struct itself */
struct foo {
  short a;
  int b;
  foo* next;
};

Observe that this easily allows to use the typedef already inside the declaration of the struct itself, and that even for struct that reference each other mutually.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • 6
    +1 for an area I missed, and add that if you use `typedef struct foo foo;` in your headers and don't provide a definition of `struct foo`, user code will have an opaque pointer (i.e. they can pass `foo *` pointers to and receive them from library functions but can't access the internal members.) This is good for data encapsulation, and a common idiom: the standard `FILE *` type is one such instance of this. – Chris Lutz Jan 15 '11 at 08:42