异质的数据结构
3.9 异质的数据结构
- 机构:struct 声明;
- 联合:union 声明。
3.9.1 结构
C语言的struct声明创建一个数据类型,将可能不同类型的对象聚合到一个对象中。结构中各个组成部分用名字来引用。类似于数组,结构的所有组成部分都存放在一段连续的区域内,而指向结构的指针就是结构第一个字节的地址。编译器维护关于每个结构类型的信息,指示每个字段(field)的字节偏移。它以这些偏移作为存储器引用指令中的位移,从而产生 对结构元素的引用。
示例:
struct rec{
int i;
int j;
int a[3];
int *p;
};
--------------------------------------
偏移 0 4 8 20 24
--------------------------------------
内容 i j a[0] a[1] a[2] p
--------------------------------------
为了访问结构的字段,编译器产生的代码要将结构的地址加上适当的偏移。下面的代码将元素r->i复制到r->j
movl (%edx), %eax ## Get r->i
mvol %eax, 4(%edx) ## Store in r->j
因为字段I的偏移量是0,所以这个字段的地址就是r的地址,为了存储到字段j,代码要将r的地址加上偏移量4。
综上所述:结构的各个字段的选取完全是在编译时处理的。机器代码不包含关于字段声明或字段名字的信息。
3.9.2 联合
联合提供了一种方式,能够规避C语言的类型系统,允许以多种类型来引用一个对象。联合声明的语法与结构的语法一样,只不过语义相差比较大。它们是用不同的字段来引用相同的存储器块。
考虑下面的声明:
struct s3{
char c;
in i[2];
double v;
};
union u3{
char c;
in i[2];
double v;
};
在一台IA32 Linux机器上编译时,字段的偏移量、数据类型S3和U3的完整大小如下:
类型 | c | i | v | 大小 |
---|---|---|---|---|
s3 | 0 | 4 | 12 | 20 |
u3 | 0 | 0 | 0 | 8 |
一个联合的大小等于它最大字段的大小。
联合的一种应用情况是,我们事先知道对一个数据结构中的两个不同字段的使用时互斥的,那么将这两个字段声明为联合的一部分,而不是结构的一部分,以减少分配空间的总量。
3.9.3 数据对齐
许多计算机系统对基本数据类型合法地址做出了一些限制,要求某种类型对象的地址必须是某个值K(通常是2、4或8)的倍数。 这种对齐限制简化了形成处理器和存储器系统之间接口的硬件设计。
无论数据是否对齐,IA32硬件都能正确工作。不过,Intel还是建议要对齐数据以提高存储器系统的性能。Linux沿用的策略是2字节的数据类型(例如short)的地址必须是2的倍数,而较大的数据类型(例如int、int*、float和double)的地址必须是4的倍数。注意,这个要求就意味着一个short类型对象的地址最低为必须是0。类似的,任何int类型的对象或指针的地址的最低两位必须都是0;
IA32的一个惯例是,确保每个栈帧的长度都是16字节的整数倍。编译器就可以在栈帧中以每个块的存储都是16字节对齐的方式类分配存储器。