c++ - 为什么 C/C++ 编译器需要在编译时知道数组的大小?

标签 c++ c

我知道 C99(以及 C++)之前的 C 标准规定堆栈上数组的大小必须在编译时知道。但这是为什么呢?堆栈上的数组是在运行时分配的。那么为什么大小在编译时很重要?希望有人向我解释编译器在编译时将如何处理大小。谢谢。

这样一个数组的例子是:

void func()
{
    /*Here "array" is a local variable on stack, its space is allocated
     *at run-time. Why does the compiler need know its size at compile-time?
     */
   int array[10]; 
}

最佳答案

要了解为什么可变大小的数组实现起来更复杂,您需要了解一下自动存储持续时间(“本地”)变量通常是如何实现的。

局部变量倾向于存储在运行时堆栈中。堆栈基本上是一个大的内存数组,它被顺序分配给局部变量,并有一个指向当前“高水位线”的索引。这个索引是堆栈指针

进入函数时,栈指针向一个方向移动,为局部变量在栈上分配内存;当函数退出时,堆栈指针向另一个方向移回,以释放它们。

这意味着局部变量在内存中的实际位置仅引用函数入口1处的堆栈指针的值来定义。函数中的代码必须通过堆栈指针的偏移量来访问局部变量。要使用的确切偏移量取决于局部变量的大小。

现在,当所有局部变量的大小在编译时固定时,堆栈指针的这些偏移量也是固定的 - 因此它们可以直接编码到编译器发出的指令中。例如,在这个函数中:

void foo(void)
{
    int a;
    char b[10];
    int c;

a可以作为 STACK_POINTER + 0 访问, b可以作为 STACK_POINTER + 4 访问, 和 c可以作为 STACK_POINTER + 14 访问.

但是,当您引入一个可变大小的数组时,这些偏移量就不能再在编译时计算;其中一些将根据数组在函数调用时的大小而有所不同。这使得编译器编写者的事情变得更加复杂,因为他们现在必须编写访问 STACK_POINTER + N 的代码。 - 从 N 开始本身各不相同,它也必须存储在某个地方。这通常意味着进行两次访问——一次访问 STACK_POINTER + <constant>。加载 N ,然后另一个加载或存储感兴趣的实际局部变量。


1.事实上,“函数入口处的堆栈指针的值”是一个非常有用的值,它有自己的名称 - 帧指针 - 许多 CPU 提供了一个单独的寄存器专用于存储帧指针。在实践中,通常是计算局部变量位置的帧指针,而不是堆栈指针本身。

关于c++ - 为什么 C/C++ 编译器需要在编译时知道数组的大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4341570/

相关文章:

c++ - 在这个特定的上下文中,从基类到派生类的 static_cast 是否被视为 "safe"?

c++ - 如何在 VS C++ 项目中使用 T4 代码生成模板?

c - 为什么我的 BST 根指针由于某些未知原因而改变?

c - C中的字符串多线程

c++ - 为什么派生类中有模板名(基类是模板的实例)?

c++ - 优化原子compare_exchange_weak

C++计算冗余字符串

c++ - 是否可以在定义函数的位置之外声明函数的属性? (海湾合作委员会)

c++ - 使用 alloca 函数时崩溃,但使用 malloc 时正常

c - 在 Swift 中读取二进制 (.hgt) 文件(将代码从 C++ 迁移到 swift)