6.7.3.4 标记
约束
若两个使用同一标记的声明声明的是同一类型,那么它们必须同属
struct、union或enum中的同一类,不能混用。若同一类型的两个声明都带成员声明列表或枚举项列表,那么:
- 一个不能嵌套在另一个里面;
- 它们必须满足兼容类型的所有要求;
- 对结构体/联合体,还要求对应成员类型必须完全相同,不能只是兼容。
形如
enum identifier且没有枚举项列表的类型说明符,只能在该枚举类型已经完整之后出现。形如
struct-or-union identifier的这种类型说明符中,不得带属性说明符序列。
语义
在同一作用域里,使用同一标记声明的结构体、联合体或枚举类型,声明的是同一个类型。
除固定底层类型枚举外,带内容定义的类型在其内容第一次定义完成、右花括号结束后,才变为完整类型。
固定底层类型枚举则在其
enum type specifier结束后立即完整。不同作用域中的同名标记,或者不同标记的声明,声明的都是不同类型。
没有标记的结构体、联合体、枚举声明,每次都会引入一个不同类型。
几种关键形式
- 下面这种形式会定义类型;如果给了标记,还会同时声明该标记:
c
struct tag { /* 成员 */ };
union tag { /* 成员 */ };
enum tag { A, B };
enum tag : int { A, B };1
2
3
4
2
3
4
- 下面这种形式会声明标记本身:
c
struct tag;
union tag;
enum tag : int;1
2
3
2
3
若某个
struct tag或union tag在别处单独出现,而当前可见范围里还没有这个标记,那么它会声明一个不完整类型并同时引入该标记。若当前已经可见同名标记,那么再写
struct tag、union tag或enum tag,就只是引用那个现有类型,不会重新声明标记。
典型用途
- 自引用结构体:
c
struct tnode {
int count;
struct tnode *left, *right;
};1
2
3
4
2
3
4
- 互相引用的结构体,最好先写前置标记声明,避免作用域敏感问题:
c
struct s2;
struct s1 { struct s2 *s2p; };
struct s2 { struct s1 *s1p; };1
2
3
2
3
- 也可以通过
typedef名改善可读性:
c
typedef struct tnode TNODE;
struct tnode {
int count;
TNODE *left, *right;
};1
2
3
4
5
2
3
4
5