简体   繁体   中英

How do structs that have been typedef-ed work in C?

Structures with tags allow you to make a instances (or whatever an instance is called in c). What about typedef structs though? If the typedef is for the struct keyword to be replaced by a type name, then every time you use the the typename aren't you just saying that you are replacing the struct keyword with the type name? Example:

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


int main()
{

    TypeName instance; // isn't this the same as writing struct instance; ?

    return 0;
}

So how does typedef work when you use it on a struct?

It defines a struct with no name and then make TypeName a name for that same struct.

If you like, you can imagine it as if the compiler creates a random name for you (some compilers actually do):

typedef struct __TOTALLY_RANDOM_NAME_wieryweuoi3u4t23423cogh234283 {
    int x;
    int y;
}TypeName;

int main()
{
    struct __TOTALLY_RANDOM_NAME_wieryweuoi3u4t23423cogh234283 instance;

    return 0;
}

If a structure definition does not have a tag, it is a different type each time it appears. For example:

int main(void)
{
    struct { double a, b; } x;
    struct { double a, b; } y = { 0, 0 };
    x = y;
}

will get an error message because x and y are incompatible types.

When a typedef is used, it makes a new name for the type . It is not like a macro replacement that repeats the previous source code; it is a name for the conceptual type, not for the source code. So this source code will not get an error message:

int main(void)
{
    typedef struct { double a, b; } T;
    T x;
    T y = { 0, 0 };
    x = y;
}

One reason otherwise identical structure definitions are considered to have different types is that we might want to use them for different purposes. For example, we might have typedef struct { double v[2]; } Point; typedef struct { double v[2]; } Point; to represent points in a plane using two coordinates and typedef struct { double v[2]; } Complex;typedef struct { double v[2]; } Complex; to represent complex number using a real part and an imaginary part, and we want these to be treated as separate types in our program.

struct { int x; int y; } struct { int x; int y; } is an anonymous structure type and it is distinct from any other structure type with exactly the same members (even though they share the same binary layout).

After the following declarations:

struct {
   int x;
   int y;
} a, b;

struct {
   int x;
   int y;
} c;

Then variable a has the same type as variable b , but does not have the same type as variable c . For the same reason, the following code has conflicting types for variable d :

extern struct {
    int x;
    int y;
} d;  // external declaration of `d`.

extern struct {
    int x;
    int y;
} d;  // INVALID: conflicting external declaration of `d`.

struct {
    int x;
    int y;
} d = { 23, 42 }; // INVALID: conflicting definition of `d`.

Type definitions (declared using the typedef keyword) are useful for defining identifiers as "typedef names" that are synonyms for specified types. A typedef declaration does not create any new types, it only creates synonyms for existing types. An appearance of the typedef name in some other declaration denotes the original type. This is particularly useful for capturing anonymous types so that they can be used in more than one declaration. For example, after the following declarations:

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

TypeName a, b;

TypeName c;

extern TypeName d;

extern TypeName d;

TypeName d = { 23, 42 };

The typedef name TypeName denotes an anonymous structure type. Variables a , b , c , and d all have this same anonymous structure type. There are no conflicts between the external declarations of variable d and its definition.

As another example, after the following declarations:

typedef struct {
   int a;
   int b;
} Type1, Type2, TypeArr1[10];

typedef Type2 TypeArr2[10];

typedef struct {
   int a;
   int b;
} Type3;

extern Type1 a;
extern Type2 a; // no conflict with previous declaration of variable `a`.
extern Type3 a; // INVALID! conflicting types for variable `a`.

extern TypeArr1 arr;
extern TypeArr2 arr; // no conflict with previous declaration of variable `arr`.
  • Type1 and Type2 denote the same type as each other.
  • TypeArr1 denotes an array type of length 10 whose element type is the same as that denoted by Type1 .
  • TypeArr1 and TypeArr2 denote the same array type as each other (having identical array length and element type).
  • Type1 and Type3 denote different types, so their use in the declarations of variable a are conflicting.

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