简体   繁体   中英

C structs don't define types?

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

据我所知,它不应该在没有C99中的typedef情况下工作(因为这只是C的工作方式),但它确实在C ++中工作,因为C ++中的struct只是一个默认情况下公共所有成员的class

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;

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; .

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++.

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 spaces 1 . 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)

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

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.

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

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.

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

Ie:

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM