不同的用途反映了该类型是否(仅)用于接口,或者是否必须知道结构信息。
符号:
typedef struct some_obj_s some_obj_t;
告诉编译器有一个带有 tagsome_obj_s
和 typedef name的结构类型some_obj_t
。如果此类型对用户来说是不透明的类型,则无需指定结构的详细信息。some_obj_t *
可以声明和使用带有参数(可能是限定的)或返回此类值的函数,而无需进一步的信息。(你甚至可以声明这种类型的extern
变量,因为编译器主要需要一个地址。)类型不完整(也称为不透明),但可以完成。
在实现的某个地方,您会找到结构类型的定义(除了最不寻常的情况),例如:
struct some_obj_s
{
...members defined...
};
如果此声明(定义)在范围内,您可以创建some_obj_t
or类型的变量struct some_obj_s
,以及指向该类型的指针。代码可以使用结构的成员。
符号:
typedef struct /* no tag */
{
...
} another_obj_t;
定义了一个无标记的结构类型。提供了类型的详细信息,因此类型是完整的。
您可能还会看到:
typedef struct yao_s
{
...members defined...
} yao_t;
这两者都使用其标记和 typedef 声明结构类型。
单独的 typedef 具有自引用结构的优势,例如列表:
typedef struct GenericList GenericList;
struct GenericList
{
void *data;
GenericList *next;
GenericList *prev;
};
如果没有单独的typedef
行,您必须struct GenericList
在结构内部编写。这意味着同样的事情;你仍然可以写它;但是使用单独的 typedef,您可以在结构中使用与稍后引用它相同的符号。
请注意,POSIX为实现保留类型名称结尾_t
。这意味着在您自己的代码中使用该约定可能很危险。
不需要为标签和 typedef 使用单独的名称(如GenericList
示例所示),尽管_s
and_t
后缀也是一个众所周知的约定。C++ 会自动将标签变成类型名,不需要显式 typedef(但允许显式 typedef),所以我通常使用相同的标签和类型名称。