总结一下,C 的类型分为:
② 函数类型
以上的三种类型都可以派生为指针类型。
对于男性(Man),他可能有妻子(wife)。如果是未婚男性,wife 就是NULL。所以,Man 这样的类型,可以声明成下面这样:
struct Man_tag { struct Woman_tag *wife; /*妻*/};
作为妻子,可以这样声明:
struct Woman_tag { struct Man_tag *husband; /*夫*/};
这种情况下,struct Man_tag 和 struct Woman_tag 是相互引用的,所以无论先声明哪一边都很麻烦。
可以像下面这样通过先声明结构体标记来回避以上问题:
struct Woman_tag; // 将 tag 提前声明struct Man_tag { struct Woman_tag *wife; /* 妻 */};struct Woman_tag { struct Man_tag *husband; /* 夫 */};
在某些环境中,结构体必须使用 typedef,所以,
typedef struct Woman_tag Woman; // 提前对 tag 进行类型定义typedef struct { Woman *wife; /* 妻 */} Man;struct Woman_tag { Man *husband; /* 夫 */};
对这种情况,在 Woman 类型的标记被声明的时候,还不知道其内容,所以无法确定它的大小。这样的类型就称为不完全类型。
因为不能确定大小,所以不能将不完全类型变成数组,也不能将其作为结构体的成员,或者声明为变量。但如果仅仅是用于取得指针,是可以使用不完全类型的。
对于指针声明来说,只要其声明的类型存在(基本类型,或已定义或声明的复合类型),便可以从其派生出指针类型。
上面的结构体 Man,就是将 Woman 类型的指针作为它的成员。之后,在定义 struct Woman_tag 的内容的时候,Woman 就不是不完全类型了。
在 C 标准中,void 类型也被归类为不完全类型。
void*类型表示为类型待定的指针,可以被赋值一个任何类型的地址,只要在指针本身操作或操作指针的指向目标时,类型显式强制转换为原始或期望的类型即可。 指针可以指向为不完全类型,同时,指针不论其目标类型如何,其大小都是固定的一个字长,所以在结构体定义中,可以定义一个自指向的指针,这样的指针并不影响结构体的整体内存分配或布局,所以被定义为链式存储(用来关联数据关系)的语法机制:
struct Node{ int data; struct Node* next; // 指针本身的大小确定(一个字长),与目标类型无关};
ref
前橋和弥《征服C指针》
-End-