跳转至

1 局部存储分配

基本概念

过程(函数、方法等):过程定义、过程调用、形参、实参

活动:过程的一次调用。

  • 相关概念:活动的生存期

活动记录:每个活动的栈帧

名字(标识符):关键字、保留字等


变量:程序语言对机器内存单元的抽象

  • 要素:名字、类型、字宽、地址、作用域、生存期
  • 绝大多数的变量都有名字;没有名字的变量:临时变量、堆中变量
  • 变量的地址 = 左值;变量的值 = 右值
  • 程序中相同的变量在不同的时间可能关联到不同的地址
  • 环境把名字映射到左值,而状态把左值映射到右值
  • 赋值改变状态,但不改变环境
  • 过程调用改变环境:不同的活动有不同的活动记录
  • 如果环境将名字 x 映射到存储单元 s,则说 x 被绑定

绑定:实体和属性之间的关联

如:count = count + 2

  • count 的类型在编译时绑定
  • count 的可能取值集合在语言设计时绑定
  • count 的值在运行时绑定
  • + 的含义在编译时确定操作数类型时绑定
  • 2 的内部表示在语言设计时被绑定

静态绑定:运行前发生并且在程序执行期间保持不变

动态绑定:运行期间发生或者在程序执行期间改变

类型绑定:变量在被引用前必须绑定到数据类型

  • 静态类型绑定 = 变量声明(显式声明、隐式声明/命名约定);方便但命名约定可能会损失可靠性
  • 动态类型绑定:根据对变量的赋值推断变量的类型;灵活,但是代价高(动态类型检查、动态存储分配、解释执行等操作),难以在编译时检测类型错误

存储绑定

  • 存储绑定:变量所绑定的内存单元的分配、回收(静态、栈、堆)
  • 生存期(lifetime):变量绑定到某个存储单元的时间区间

控制绑定

  • 作用域(scope):一个声明起作用的程序部分(局部变量、非局部变量)
  • 命名空间(namespace):不同命名空间的同名符号含义互不相干

同名变量处理:如最近(小)嵌套作用域规则

并列程序块复用存储空间

image-20221228122004270

全局变量处理:如 Python 中全局变量可以在函数中引用,但是只能对在函数中声明为 global 的全局变量赋值。


活动记录(activation record)的常见布局

image-20221228123753783

局部数据的布局

  • 字节是可编址内存的最小单位
  • 变量所需的存储空间可以根据其类型而静态确定
  • 一个过程所声明的局部变量,按这些变量声明时出现的次序,在局部数据域中依次分配空间
  • 局部数据的地址可以用相对于活动记录中某个位置的地址来表示
  • 数据对象的存储布局还需考虑对齐问题

对齐的实例

char: 1, long: 4, double: 8

struct a {
    char c1; // 位置:0
    long i;  // 位置:4,5,6,7(位置1,2,3因对齐被浪费)
    char c2; // 位置:8
    double f;// 位置:16~23(位置9~15因对齐被浪费)
};

struct b {
    char c1; // 位置:0
    char c2; // 位置:1
    long i;  // 位置:4~7
    double f;// 位置:8~15
};

例题

一个 C 语言程序及其在 x86/Linux 操作系统上的编译结果如下。根据生成的汇编程序来解释程序中四个变量的存储分配、 生存期、作用域和置初值方式等方面的区别。

static long aa = 10;
short bb = 20;
extern int f();
int func() {
    static long cc = 30;
    short dd = 40;
    cc = f(cc, dd); // 此处有变量提升
}

见 07-runtime-part1.pdf

本文阅读量