tags:

views:

372

answers:

12

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"?

A: 

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
+6  A: 

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
PP
Mikael is right, C++ does not require you to use struct while declaring types of the structure. Why was the answer down voted?
ardsrk
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
+1  A: 

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
+6  A: 

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
A struct does define a type. That's why after defining `struct Foo`, I can declare a variable `struct Foo a`.
Chuck
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
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
+1  A: 

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
structs are types. The name of the type defined by struct Point {} is "struct Point"
Pete Kirkham
Leading underscore followed by a capital letter identifiers are reserved for the implementation.
Logan Capaldo
A: 

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
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
@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
I was giving examples based on the OP's example, using his names, variables and types. I'll edit the answer, though.
Tim Post
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
+1  A: 

if you are new to C I suggest you read the book the C programming language

it will rapidly get you familiar with the language

Alon
+4  A: 

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
A: 

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
+1  A: 

Ah, thx, now I got it ^^...

Trollhorn
You should place this as a *comment* to the answer that helped you. Also, you can click on the green checkmark to say "this is the correct answer". Welcome to stackoverflow.
voyager
+3  A: 

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
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..
+1  A: 

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