何时分配块作用域变量

4
如果我有一个C函数
int foo(int input)
{
    int x = 5;
    if( input == 0 ){
        int y = 6;
    } else {
        int z = 7;
    }
}

我知道当我们进入函数时,栈指针会被调整,为int x语句腾出空间。我也知道yz仅存在于它们各自的块作用域中。但是它们的空间是何时以及如何分配的呢?


据我所知,只要编译器确保变量在逻辑上应该在作用域内时,它就可以选择自己的分配策略。我认为规范并没有规定具体的分配方式。 - Eric J.
4
那些变量?等到优化器完成时,就不会再改变了。 - WhozCraig
1
我知道它们会被优化掉。为了简洁起见,我没有加上“...并执行某些操作...”我将在以后的问题中加入。 - BostonJohn
2个回答

6
只要空间至少持续到变量的生命周期结束,编译器就会分配空间。通常情况下,函数中所有自动变量的空间都在函数开始时在栈上分配,并在函数返回时被释放。如果不需要地址,一些变量可能会被放置在寄存器中。由于你的变量从未被使用,它们可能根本不存在。
更新:如评论中所提到的,C语言(但尚未C++)允许动态大小的局部数组。显然,这些数组的空间无法分配,直到知道了其大小。

一些编译器可能会在执行进入定义变量的作用域或遇到定义时为变量分配空间。这意味着在 OP 的示例中,Y 和 Z 变量将在执行进入它们各自的语句块时分配,而不是在函数开始时分配。 - Thomas Matthews
甚至不是因为分配没有影响。因此,取决于编译器,甚至函数本身也可能被完全删除。 - Sebastien
@ThomasMatthews:确实,编译器可以这样做。但是,在大多数平台上,这比单个分配的效率要低,因此通常不会这样做。 - Mike Seymour
@MikeSeymour:每个C 1999或2011实现必须支持在任意点自动(类似堆栈)分配,而不仅仅是函数入口。考虑void foo(int x) { … int n = bar(x); char c[n]; … }。编译器无法在进入foo时为c分配空间,因为所需空间未知。对于那些既具有可预先计算大小又在每个可能的分支中使用或者很小的对象,实现应该仅在函数开头进行分配。 - Eric Postpischil
@EricPostpischil:好的,我是在考虑C++,在那里没有动态大小的对象(至少要到明年才有)。正如你所说,它们的分配将不得不推迟到知道大小为止。 - Mike Seymour

0
int foo(int input)
{ // BLOCK 1
    int x = 5;
    if( input == 0 )
    { // BLOCK 2
        int y = input * (x + 6);
        // other code here
    }
    else
    { // BLOCK 3
        int z = input + x;
        // other code here
    }
}

编译器能够优化其中大部分,但高级语言规则如下:

xBLOCK 1 和任何子块 (BLOCK 2BLOCK 3) 中都是有效的。 y 只在 BLOCK 2 中有效。 z 只在 BLOCK 3 中有效。

编译器进行的第一次通常会保留这些规则。随后的通常会看到您未使用变量 (或优化它们的使用方式) 并可能移动它们或根本不将它们存储在内存中 (例如,它们可能只是放在寄存器中),因此试图将它们在高级语言中的作用域与汇编中的优化方式相等是愚蠢的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接