计算机基础

异质的数据结构

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的完整大小如下:

类型civ大小
s3041220
u30008

一个联合的大小等于它最大字段的大小。

联合的一种应用情况是,我们事先知道对一个数据结构中的两个不同字段的使用时互斥的,那么将这两个字段声明为联合的一部分,而不是结构的一部分,以减少分配空间的总量。

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字节对齐的方式类分配存储器。

关于作者

程序员,软件工程师,java, golang, rust, c, python,vue, Springboot, mybatis, mysql,elasticsearch, docker, maven, gcc, linux, ubuntu, centos, axum,llm, paddlepaddle, onlyoffice,minio,银河麒麟,中科方德,rpm