C和指针_第10章_结构和联合_学习笔记
扫描二维码
随时随地手机看文章
1.结构
struct { int a; char b; float c; }x; struct { int a; char b; float c; }y[20], *z;
警告:以上两个声明被编译器当做两个截然不同的类型。即y和z为同一类型,但与x类型不用。
使用结构标签声明结构:
struct SIMPLE{ int a; char b; float c; };
此时SIMPLE是结构标签,使用标签创建需要如下代码:
struct SIMPLE x; struct SIMPLE y[20], *z;
使用typedef定义一个新类型:
typedef struct { int a; char b; float c; }SIMPLE;
此时SIMPLE是一个类型名,使用创建变量如下所示:
SIMPLE x; SIMPLE y[20], *z;
1.5结构自引用
结构中不能包含类型为结构本身的成员,但可以包含一个指向类型为结构本身的成员的指针。注意:
//错误 typedef struct { int a; char b; float c; struct SIMPLE *d; }SIMPLE; //正确 struct SIMPLE{ int a; char b; float c; struct SIMPLE *d; };
同时使用结构标签和typedef也是正确的声明方式:
typedef struct SIMPLE{ int a; char b; float c; struct SIMPLE *d; }SIMPLE;
3.结构的内存分配
编译器按照成员列表的顺序一个接一个的给每个成员分配内存,但要满足正确的编剧对齐要求。一般而言:
struct SIMPL{ int b; char a; char c; };
比下面声明要占用更少的内存:
struct SIMPL{ char a; int b; char c; };
sizeof操作符可以获得一个结构的整体长度,包括因边界对齐而跳过的字节。如果必须确定结构某个成员的实际位置,应该考虑边界对齐因素,可以使用offsetof宏(定义于stddef.h)。
offsetof( type, member );
type是结构类型,member是需要的成员名。
4.结构做函数参数。
为提示效率,对较大的结构体传递参数时采用指针会比传递值更优效率。担心传递指针会导致函数修改结构体成员值可采用如下代码:
void func( SIMPLE const *simple);
为提示效率还可以采用寄存器类型,即如下代码:
void func( register SIMPLE const *simple);
5.位段
位段的声明和结构体类似,但其的成员是一个或多个位的字段。这些不同长度的字段实际存储于一个或多个整型变量中。
struct CHAR { unsigned ch : 7; unsigned font : 6; unsigned size : 19; };
注意:
1.注重可移植性的程序应避免使用位段。
2.位段中位的最大数目。声明于32位机的位段可能在16位的机器上无法运行。
3.位段中的成员在内存中是从左往右分配还是从右往左分配。
4.当一个声明指定了两个位段,第2个位段比较大,无法容纳于第1个位段剩余位时,编译器可能把第2个位段放在内存的下一个字,也可能直接放在第1个位段后面,从而在两个内存位置的边界形成重叠。
6.联合
联合中的所有成员引用的是内存中的相同位置,所占内存空间为成员中占用内存空间最大的成员所占的内存空间。因此,若成员的占用内存空间大小差距悬殊,采用在联合中存储指向不同成员的指针而不是直接存储成员本身的方法可以节省内存。联合变量可以被初始化,但这个初始值必须是联合第1个成员的类型,并且必须位于一对花括号内:
union { int a; float b; char c[4]; } x = { 5 };
结构和联合的结合使用以节省内存:
struct VARIABLE { enum { INT, FLOAT, STRING } type; union { int i; float f; char *s; }value; };