第十章 结构和联合
这个部分先介绍了.运算符,可以供直接访问,还介绍了->运算符,它代替结构体指针的间接访问操作(*struct).xxx
这一章新手理解起来不算太难,没有学过操作系统的话理解位段、对齐等概念会有一些问题。
越发的说明了指针和内存绝对是C的核心。
总结:
结构声明列出了结构包含的成员列表,不同类型的值可以存储在一起。
不同的结构声明即使他们的成员列表相同也被认为是不同的类型。
声明结构时使用typedef创建一种新类型是一个好方法。
typedef struct
{
int a;
char b;
float c;
}simple;
跟结构标签的结果几乎相同。区别在于simple现在是一个类型名而不是结构体,以后声明就是下面这个样子。
simple x;
simple y[20], *z;
结构不能包含类型也是这个结构的成员,否则在分配地址的时候,会出现无穷大。但是可以包含一个指向这个结构的指针。
这个常常用在链式结构中。为了声明两个结构,每个结构都包含一个指向对方的指针的成员。
初始化的时候可以由一个花括号包围的值列表进行初始化。
编译器为一个结构变量的成员分配内存时要满足它们的边界对齐要求。在实现结构存储的边界对齐时,可能会浪费部分空间。根据边界对齐要求降序排列结构成员可以最大限度地减少结构存储中浪费的内存空间。
如果想要减少对齐造成的损失,一般来说声明的过程中要降序排列。可以利用offstof宏(stddef.h)+sizeof来找个更好的办法。
结构可以作为形参传递给函数,也可以作为返回值返回但是绝对不提倡!!!严重浪费内存空间。
最好形参和返回值都用指针,如果怕修改结构本身,那么就加个const!
位段个人不是理解很深,理解来看是可以将长度为奇数的值包装在一起节省空间。
Union和struct是两个不同的故事。所有Union的成员都存储于同一个内存位置。也可以进行初始化,但是初始化必需与联合第一个成员类型匹配。
关于初始化:
union{
int a;
float b;
char c[4];
} x = {5};
这样就把x.a初始为5。
警告:
1、具有相同成员列表的结构声明产生不同类型。
这就像函数一样,跟声明关系很大。
2、使用typedef为一个自引用的结构定义名字时应该小心。
自引用一定要记住,要引用指针。
3、向函数传递结构参数是低效的。
要对内存的形参进行拷贝,这份拷贝放在内存里实在是太浪费空间。
编程提示:
1、typedef声明放在头文件中。到是用到就#include回来。
2、结构成员的最佳排列形式并不一定就是考虑边界对齐而浪费内存空间最少的那种排列方式。
很显然,为了对齐,有时候你不得不打乱声明的顺序,从而导致可读性的降低。
3、把位段成员显式得声明为signed int 或者 unsigned int类型。
4、位段是不可抑制的。
5、位段使源代码中位的表达式更加清楚。
问题:
1、成员和数组元素有什么区别?
成员可以具备不同的类型,数组不行。
2、结构名和数组名有什么不同?
数组名是一个指针常量。但是结构名就是个标签tag,跟class名类似,没有实例的话,是不会对其分配内存的。
3、结构的声明:
struct tag{member-list } variable-list;
tag、member-list、variable-list三者必需有二。