# 2.6 结构体与联合体 ## 2.6.1 结构体 数组中保存的是一组相同类型的数据,而结构体中可以保存一组不同类型的数据,他是一类数据的聚合。 ```cpp // 元素 A 和 B 占用不同存储空间. struct _A_STRUCT { short A; // 内部元素 A. char B; // 元素 B. int C; // 元素 C. }AStruct = {15, 8, 32}; struct _A_STRUCT* pAStruct = &AStruct; // pAStruct 是一个结构体指针. printf("%d\n", sizeof(AStruct)); // AUnion 的长度为 8(涉及到内存对齐). printf("A=%d\n", AStruct.A); // 输出 15. printf("B=%d\n", pAStruct->B); // 输出 8. ``` 结构体变量使用 “.” 来访问内部元素,而结构体指针使用 “->” 来访问内部元素。 我们看到,上面定义结构体指针的方法非常繁琐,我们有更简单的方式: ```cpp struct _A_STRUCT { short A; char B; int C; }A_STRUCT; // 通过 typedef 将 A_STRUCT 定义成了 struct _A_STRUCT 类型. A_STRUCT AStruct = {15, 8, 32}; // 这样用起来就方便了. A_STRUCT* pAStruct = &AStruct; // 嗯,确实方便多了. ``` ## 2.6.2 联合体 联合体则为同一地址空间起了两或多个名字。 ```cpp // 元素 A 和 B 占用同一存储空间. union _A_UNION { short A; char B; }AUnion; printf("%d\n", sizeof(AUnion)); // AUnion 的长度为 2. ``` 访问联合体内部元素的方法与结构体类似。 联合体也支持 typedef,方法与结构体一致。 ## 2.6.3 结构体、联合体混合使用 结构体中可以嵌套联合体: ```cpp typedef struct _SuperHero { char* name; char* actor; union { unsigned short ShieldLevel; unsigned short IronLevel; }; // 结构体中允许使用匿名联合体. }SuperHero; void InitSuperHero(SuperHero* hero) { if(0==strcmp("Captain America", hero->name)) { hero->ShieldLevel = 3; } else if(0==strcmp("Iron Man", hero->name)) { hero->IronLevel = 4; } } ``` 除了结构体嵌套联合体外,还允许结构体嵌套结构体、联合体嵌套联合体、联合体嵌套结构体等,由此可以组合成复杂的数据结构。 ## 2.6.4 结构体、联合体、数组混合使用 可以创建结构体数组,联合体数组,或更加复杂数据结构类型的数组。 ```cpp typedef struct _SuperHero { char* name; char* actor; union { unsigned short ShieldLevel; unsigned short IronLevel; }; // 结构体中允许使用匿名联合体. }SuperHero; SuperHero MarvelHeros[8000]; // 听说漫威有 7000 多个超级英雄,多余空位预留吧! MarvelHeros[0].name = "Black Widow"; MarvelHeros->actor = "Scarlett Johansson"; ``` ## 2.6.5 结构体与内存对齐 计算机有一个特点,如果访问的内存地址是自然对齐的(由计算机地址总线位宽决定),那么访问速度就比较快。如果不是自然对齐的,访问速度就会慢一些。基于此特性,编译器会对我们的程序进行一些优化,使得没有特殊的情况下,变量总是自然对齐。 编译器的这个特性造成了一些奇怪的现象。 ```cpp struct { char a; char b; }sta; struct { char a; char b; char c; }stb; struct { char a; short b; int c; }stc; printf("%d\n", sizeof(sta)); // 输出 2. printf("%d\n", sizeof(stb)); // 输出 4. ``` 由于 ## 练习