简体   繁体   English

为什么允许`typedef struct xx`?

[英]Why is `typedef struct x x` allowed?

I was reading the book modern C and was suprised to find that the following code works 我正在阅读《 现代C》这本书,很惊讶地发现以下代码有效

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

int main() {
   point p = { .x = 1, .y = 2 };
}

However, the book does not go in detail about that. 但是,这本书没有详细介绍。 How does that work? 这是如何运作的? Why does point in main() refer to the typedef since struct point is defined after that? 为什么main()中的point引用typedef因为struct point之后定义的?

The line typedef struct point point; 线typedef struct point point; does two things: 做两件事:

  • It creates a forward declaration of struct point 它创建struct point前向声明
  • It creates a type alias for struct point called point . 它为名为point struct point创建类型别名。

Forward declarations are useful if you need to know a struct exits before it is fully defined, for example: 如果您需要在结构完全定义之前就知道其退出,则前向声明很有用,例如:

typedef struct x X;

typedef struct y {
    int a;
    X *x;
} Y;

 struct x {
     int b;
     Y *y;
 };

You can use struct foo in many places before struct foo { ... } is defined. 在定义struct foo { ... }之前,可以在许多地方使用struct foo This is known as an "incomplete type". 这称为“不完整类型”。

It's useful because it lets you define abstract types: 这很有用,因为它使您可以定义抽象类型:

foo_header.h foo_header.h

struct foo;  // abstract
struct foo *foo_create(void);
void do_stuff_with(struct foo *);
void foo_destroy(struct foo *);

This way users of the library can use struct pointers and functions that work on these pointers without knowing how the struct is actually defined, which is nice for encapsulation. 这样,库的用户可以使用结构指针和在这些指针上工作的函数,而无需了解结构的实际定义方式,这对于封装非常有用。

It's also used in recursive types: 它也用于递归类型:

struct node {
    int data;
    struct node *next;  // struct node isn't defined yet!
};
// here the definition of struct node is complete

C supports it because it's easy to implement: To compile code that uses struct foo * , the compiler only has to know how big the pointer is. C支持它,因为它易于实现:要编译使用struct foo *代码,编译器只需知道指针的大小即可。 It doesn't care about the struct members. 它不在乎结构成员。

Similarly, in your typedef example, the compiler doesn't need to know the details of the struct to create a type alias for it. 同样,在您的typedef示例中,编译器不需要知道结构的详细信息即可为其创建类型别名。

This works because C has multiple name spaces : 之所以可行,是因为C具有多个名称空间

  • labels (disambiguated by goto or trailing : ); 标签(由消除歧义goto或尾随: );
  • tag names for struct , enum , and union (disambiguated by the struct , union , or enum keywords): structenumunion标记名称(由structunionenum关键字消除歧义):
  • names for struct and union members (disambiguated by a leading . or -> , each struct or union type acts as its own namespace, so different struct and union types can use the same member names); structunion成员的名称(由前导.->消除歧义,每个structunion类型都充当其自己的名称空间,因此不同的structunion类型可以使用相同的成员名称);
  • all other identifiers (variable and function names, typedef names, enumeration constants, etc.). 所有其他标识符(变量和函数名称,typedef名称,枚举常量等)。

So you can use the same name as a label, a tag name, a member name, and a regular identifier all in the same code, and the compiler is able to distinguish between them: 因此,您可以在同一代码中使用与标签相同的名称,标签名称,成员名称和常规标识符,并且编译器可以区分它们:

struct x { int x; }; // tag name, member name

void foo( struct x x ) // tag name, all other identifiers
{
  if ( x.x ) // all other identifiers, member name
    goto x;  // label name

  // do something here

  x: printf( "At label x\n" ); // label name
}

This example comes straight from C standard, Section 6.7.2.3: 此示例直接来自C标准的6.7.2.3节:

The following alternative formulation uses the typedef mechanism: 以下替代公式使用typedef机制:

typedef struct tnode TNODE;
struct tnode {
 int count;
 TNODE *left, *right;
};
TNODE s, *sp;

What it does it forward declares struct, and than creates a type alias for it. 它向前执行的操作将声明struct,然后为其创建类型别名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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