我正在读modern C这本书,很惊讶发现以下代码有效
typedef struct point point;
struct point {
int x;
int y;
};
int main() {
point p = { .x = 1, .y = 2 };
}
但是,这本书没有详细介绍。这是如何运作的?为什么point
中的main()
引用typedef
,因为struct point
是在之后定义的?
答案 0 :(得分:6)
第typedef struct point point;
行有两件事:
struct point
struct point
创建了一个类型别名,称为point
。如果您需要在结构完全定义之前就知道其退出,则前向声明非常有用,例如:
typedef struct x X;
typedef struct y {
int a;
X *x;
} Y;
struct x {
int b;
Y *y;
};
答案 1 :(得分:2)
在定义struct foo
之前,可以在许多地方使用struct foo { ... }
。这就是所谓的“不完整类型”。
它很有用,因为它使您可以定义抽象类型:
foo_header.h
struct foo; // abstract
struct foo *foo_create(void);
void do_stuff_with(struct foo *);
void foo_destroy(struct foo *);
通过这种方式,库的用户可以使用结构指针和在这些指针上工作的函数,而无需了解结构的实际定义方式,这对于封装非常有用。
它也用于递归类型:
struct node {
int data;
struct node *next; // struct node isn't defined yet!
};
// here the definition of struct node is complete
C之所以支持它,是因为它易于实现:要编译使用struct foo *
的代码,编译器只需知道指针的大小即可。它不在乎struct成员。
类似地,在您的typedef
示例中,编译器不需要知道结构的详细信息即可为其创建类型别名。
答案 2 :(得分:2)
这有效,因为C具有多个名称空间:
goto
或结尾的:
消除歧义); struct
,enum
和union
的名称(通过struct
,union
或enum
关键字进行歧义):< / li>
struct
和union
成员的.
或->
消除,每个struct
或union
类型都充当其名称自己的名称空间,因此不同的struct
和union
类型可以使用相同的成员名称); 因此,您可以在同一代码中使用与标签,标签名称,成员名称和常规标识符相同的名称,并且编译器可以区分它们:
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
}
答案 3 :(得分:1)
此示例直接来自C标准的6.7.2.3节:
以下替代公式使用typedef机制:
typedef struct tnode TNODE;
struct tnode {
int count;
TNODE *left, *right;
};
TNODE s, *sp;
它转发的内容声明了struct,然后为其创建了类型别名。