一、双重身份
如下定义了一个 School 结构体:
typedef struct School { int a; int b; }SCHOOL_S; SCHOOL_S stSch;
下面我们来输出一下 stSch 以及成员变量 a 和 b 的地址:
int main() { printf("stSch 的地址[%p]n", &stSch); printf(" a 的地址[%p]n", &stSch.a); printf(" b 的地址[%p]n", &stSch.b); return 0; }
输出结果如下:

有没有发现什么不得了的事情——结构体 school 的地址与第一个成员变量 a 的地址相同,也就是说变量 a 的地址既是 school * 类型,又是 int * 类型。脑海中突然冒出一个大胆的想法,如果我将 a 的地址强制类型转化为 SCHOOL_S * 类型呢:
int main() { stSch.a = 10; stSch.b = 20; SCHOOL_S *pstSch = (SCHOOL_S *)&stSch.a; printf("a = %dn", pstSch->a); printf("b = %dn", pstSch->b); return 0; }
输出结果如下:

Amazing~
二、妙用
通过上边的小测试,我们发现了 struct 的第一个成员变量的地址有双重身份,那么该如何使用呢?
对于两个不同的结构体:
typedef struct Teacher { char name[10]; /* 姓名 */ int id; /* 职工编号 */ }TEACHER_S; typedef struct School { char name[10]; /* 校名 */ int cnt; /* 教职工个数 */ }SCHOOL_S; SCHOOL_S school; TEACHER_S teacher;
void Init() { strncpy(stSchool.name, "School", sizeof(stSchool.name) - 1); stSchool.cnt = 1; strncpy(stTeacher.name, "Teacher", sizeof(stTeacher.name)); stTeacher.id = 1; }
如何在得知 school 的情况下得到 teacher 的信息呢?你或许可以这么做:在 School 中新增 Teacher 的指针变量,使其指向 teacher。
typedef struct School { char name[10]; /* 校名 */ int cnt; /* 教职工个数 */ struct Teacher *pstTeacher; /* 【Add】指向 Teacher 的指针变量 */ }SCHOOL_S;
int main() { Init(); stSchool.pstTeacher = &stTeacher; }
这也不失为一种方法,但怎么样才能用到第一个成员变量的「双重身份」这个信息呢?
下面让我们对结构体 School 和 Teacher 做个简单修改:
typedef struct List { struct List *next; }LIST_S; typedef struct Teacher { LIST_S head; /* 【Add】单链表头结点 */ char name[10]; /* 姓名 */ int id; /* 职工编号 */ }TEACHER_S; typedef struct School { LIST_S head; /* 【Add】单链表头结点 */ char name[10]; /* 校名 */ int cnt; /* 教职工个数 */ }SCHOOL_S;
int main() { Init(); stSchool.head.next = &stTeacher.head; TEACHER_S *pstTeacher = (TEACHER_S *)stSchool.head.next; printf(" stTeacher 的地址为[%p]n", &stTeacher); printf("pstTeacher 的地址为[%p]n", pstTeacher); return 0; }
输出结果如下:

是不是很神奇~