C 语言 struct 第一个成员变量的妙用


一、双重身份

如下定义了一个 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;
}

输出结果如下:

image-20220911221024068

有没有发现什么不得了的事情——结构体 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 = %d\n", pstSch->a);
    printf("b = %d\n", pstSch->b);

    return 0;
}

输出结果如下:

image-20220911221108117

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;
}

输出结果如下:

image-20220911223739727

是不是很神奇~