Вы можете использовать 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 *
, компилятору нужно только знать, насколько велик указатель.Он не заботится о членах структуры.
Аналогично, в вашем примере typedef
компилятору не нужно знать детали структуры, чтобы создать для нее псевдоним типа.