要理解为什么可变大小的数组实现起来更复杂,您需要了解一些自动存储持续时间(“本地”)变量通常是如何实现的。
局部变量往往存储在运行时堆栈上。堆栈基本上是一个大的内存数组,它按顺序分配给局部变量,并具有指向当前“高水位线”的单个索引。这个索引是堆栈指针.
当进入一个函数时,栈指针向一个方向移动,为局部变量分配栈上的内存;当函数退出时,堆栈指针向另一个方向移回,以释放它们。
This means that the actual location of local variables in memory is defined only with reference to the value of the stack pointer at function entry1. The code in a function must access local variables via an offset from the stack pointer. The exact offsets to be used depend upon the size of the local variables.
现在,当所有局部变量的大小在编译时固定时,堆栈指针的这些偏移量也是固定的 - 因此它们可以直接编码到编译器发出的指令中。例如,在这个函数中:
void foo(void)
{
int a;
char b[10];
int c;
a
可能会被访问为STACK_POINTER + 0
, b
可能会被访问为STACK_POINTER + 4
, and c
可能会被访问为STACK_POINTER + 14
.
但是,当您引入可变大小的数组时,这些偏移量将无法再在编译时计算;其中一些将根据函数调用时数组的大小而变化。这使得编译器编写者的事情变得更加复杂,因为他们现在必须编写访问的代码STACK_POINTER + N
- 从那时起N
它本身不同,它也必须存储在某个地方。通常这意味着进行两次访问 - 一次访问STACK_POINTER + <constant>
加载N
,然后另一个加载或存储感兴趣的实际局部变量。
1. In fact, "the value of the stack pointer at function entry" is such a useful value to have around, that it has a name of its own - the frame pointer - and many CPUs provide a separate register dedicated to storing the frame pointer. In practice, it is usually the frame pointer from which the location of local variables is calculated, rather than the stack pointer itself.