4

I've just started learning C with a professional Java background and some (if no too much) C++ knowledge, and I was astonished that this doesn't work in C:

struct Point {
    int x;
    int y;
};

Point p;

p.x = 0;
p.y = 0;

It seems that I have to declare p using struct Point as the type or using a typedef. Does this code works in C99? Or is this a "C++ thing"?

Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319
Trollhorn
  • 229
  • 1
  • 3
  • 5
  • 1
    Declare p as `struct Point p;`. You can use typedefs but I would recommend you get into the practice of referring to your type as `struct Point`. – PP. Nov 15 '09 at 14:54
  • @PP: I second that: http://stackoverflow.com/questions/1675351/typedef-struct-vs-struct-definitions/1675507#1675507 – Christoph Nov 15 '09 at 15:23
  • @PP Why? What wrong with the typedef in your eyes? – Grumdrig Nov 15 '09 at 15:41
  • @Grumdrig: I've never advocated re-defining a language through typedefs. It makes code maintenance and reviews more difficult. If something is a struct, say so. There, of course, are situations whereby different int types are better served as typedefs. But I don't believe there is often a good case for doing the same to structs. Again, this is anti-Google-Go philosophy whereby keywords are seen as evil and instead capitalisation is used to differentiate between public/private functions; but I prefer to be explicit. – PP. Nov 15 '09 at 19:23
  • @Grumdrig - it's a pain to add a const or const pointer "modifer" to a typedef that already has a const or even just a pointer in. – Pod Nov 16 '09 at 00:11

10 Answers10

8

As far as I know, it shouldn't work without a typedef in C99 either (as this is simply the way C works), but it does work in C++ as a struct in C++ is just a class with all members public by default.

Mikael Auno
  • 8,990
  • 2
  • 21
  • 16
  • Down-voted because this most definitely has worked since K&R C. There is a big difference between a `typedef` and a `struct` or `enum`. – PP. Nov 15 '09 at 14:58
  • 1
    Mikael is right, C++ does not require you to use struct while declaring types of the structure. Why was the answer down voted? – ardsrk Nov 15 '09 at 14:58
  • Ah, re-upvoting as misread the question/answer; technically Mikael is correct, a typedef is required if the struct typename is desired without the `struct` keyword beforehand. As a long-time user of C I stand by my recommendation that the type (struct) is explicitly stated. – PP. Nov 15 '09 at 15:04
5

No, a struct do not define a new type. What you need is:

typedef struct {
   int x; int y;
} Point;

Now Point is new type you can use:

Point p;
p.x = 0; p.y = 0;
Remo.D
  • 16,122
  • 6
  • 43
  • 74
  • 3
    A struct does define a type. That's why after defining `struct Foo`, I can declare a variable `struct Foo a`. – Chuck Nov 16 '09 at 00:01
  • 2
    Right; the point of confusion is that the struct *tag* does not serve as the type name by itself; it must be preceded by the `struct` keyword. – John Bode Nov 16 '09 at 01:17
  • You're right, I should have been more precise. A structure like "struct tag { ... };" does not set 'tag' as a new type. Of course you can use that tag to specify that a variable has that structure as in "struct tag var;". It seemed to me that the OP was not clear on the role that the struct tag plays vs. the type one defines with typedef. – Remo.D Nov 16 '09 at 10:19
4

struct Point is the type just like union Foo would be a type. You can use typedef to alias it to another name - typedef struct Point Point;.

D.Shawley
  • 58,213
  • 10
  • 98
  • 113
4

In C there is no confusion between

struct Point {
    int x;
    int y;
};

and

union Point {
    int x;
    int y;
};

which are two different types called struct Point and union Point respectively.

The C99 standard section 6.7.2.1 states:

6 Structure and union specifiers have the same form. The keywords struct and union indicate that the type being specified is, respectively, a structure type or a union type.

7 The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit.

So it most unequivocally declares a type. The syntax for type names in C is given in sections 6.7.6 and includes the specifier-qualifier-list from 6.7.2, which takes the form of struct-or-union identifier.

Does this code works in C99? Or is this a "C++ thing"?

No, C99 does not decide to promote structure types over enum types and union types with the same name. It is a "C++ thing", as struct and classes are mostly the same thing in C++, and classes are important to C++.

Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
  • Actually, I believe there is confusion, or at least there used to be - the tag namespace being shared between `struct`, `union`, and `enum`, and I've even heard some people suggest that it may be valid to declare `struct foo bar;` when `foo` was defined as a `union` but never as a `struct`. Not sure what the current state of affairs is, but it's a messy subject. – R.. GitHub STOP HELPING ICE Sep 22 '10 at 04:00
2

So...

Point           a tag
struct Point    a type

typedef struct {
    . . .
} Point_t;

Point_t         a type

I often see a why? written between the lines. After all, it does seem perfectly reasonable to just say Point x;, so why can't you?

As it happens, early implementations of C established a separate name space for tags vs other identifiers.There are actually 4 name spaces1. Once the language was defined this way, it was then not possible to allow the struct tag to be used as a type because then all existing code with name collisions between ordinary identifiers and tags would be suddenly in error.


1. The 4 name spaces are:
-- label names (disambiguated by the syntax of the label declaration and use);
-- the tags of structures, unions, and enumerations (disambiguated by following any) of the keywords struct, union, or enum);
-- the members of structures or unions; each structure or union has a separate name space for its members (disambiguated by the type of the expression used to access the member via the . or -> operator);
-- all other identifiers, called ordinary identifiers (declared in ordinary declarators or as enumeration constants)

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
1

It doesn't work in C99, it is a C++ thing. You have to either say struct Point or use a typedef in C.

Robert Gamble
  • 106,424
  • 25
  • 145
  • 137
1

Structs are not types. You can create a point from a struct as follows:

struct Point p;
p.x = 0;
p.y = 0;

If you want to use a struct as a type, you have to typedef it. This works in both C and C++:

typedef struct _point {
    int x;
    int y;
} Point;

Always give your struct a name though, if you have to forward declare it to be able to have pointers to a struct of the same type or circular dependencies.

Armin Ronacher
  • 31,998
  • 13
  • 65
  • 69
1

In C, structs can have two kinds of names: a tag name, and a type name. A tag name can only be used if it's prefixed with struct, like:

struct mytag { int a; }
struct mytag mystruct;

A typedef allows you to define both a tag name and a type name. The type name can be used without a struct prefix:

typedef struct mytag { int a; } mytype;
mytype mystruct; // No struct required
Andomar
  • 232,371
  • 49
  • 380
  • 404
0

That's the way C works. In C you have to say:

typedef struct Point {
    int x;
    int y;
} Point;

And then you'll have a type called Point that does what you want.

In C++ it's enough to define it the way you did.

Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319
0

You first need to make Point a type like :

typedef struct Point {
    int x;
    int y;
} Point;

This allows you to use Point as a type, or struct Point

I.e:

Point *p;

sizeof(struct Point);

Some people prefer to make the name of the structure different from the type being created, such as:

typedef struct _point {
       ...
} Point;

You'll run into both. The last example tells me that I should not use struct _point, its not meant to be exposed except as the type Point.

Tim Post
  • 33,371
  • 15
  • 110
  • 174
  • 4
    The last example tells you that behaviour is undefined by the C standard. Tag names (in fact all identifiers) beginning with an underscore and an uppercase letter are reserved. Of course, usually non-portable code is fine - if it passes the tests today then who cares if it will still work tomorrow, right? But why rely on _Point not being actually used by the current version of your current compiler, when you don't have to? – Steve Jessop Nov 15 '09 at 15:06
  • @Steve - absolutely correct. Never use a leading underscore followed by an uppercase letter (this is in paragraph 4 of section 6.10.8 for C99) – D.Shawley Nov 15 '09 at 15:16
  • I was giving examples based on the OP's example, using his names, variables and types. I'll edit the answer, though. – Tim Post Nov 15 '09 at 16:08
  • Now you have the same problem if the typedef has file scope (in which case underscore followed by a lowercase letter is also reserved). It's OK in a function body, though. Initial underscores are pretty much best avoided, unless you're writing bits of the implementation (for instance if you're writing the standard headers to go with a compiler). The common portable forms I've seen are `typedef struct Point { ... } Point;` and `typedef struct Point_tag { ... } Point;`. The reason for "_tag" is that the identifier that comes after struct is in the so-called "tag namespace". – Steve Jessop Nov 16 '09 at 00:31