懒惰地在C函数内创建自动变量

时间:2015-11-11 16:03:33

标签: c memory assembly compiler-optimization dynamic-allocation

我对这样的C代码感到好奇:

void test(int y){
   if (y) {
      int x = 1;
      printf("Test: %d", x + y);
   }
   // other important code (don`t use x var)
}

x变量的必要性取决于y。 例如:如果我们调用test(0),我们不需要为x变量分配空间,因为test(1)调用x变量必须存在于内存中。

现代编译器使用这种技术吗?

3 个答案:

答案 0 :(得分:2)

编译器更可能的优化是

void test(int y){
   if (y) {
      printf("Test: %d", 1 + y);
   }
   // other important code (don`t use x var)
}

然后我们在任何一种情况下都不需要x

答案 1 :(得分:1)

正如Sourav Ghosh所说,“你无法确定!”但是,让我给出编译器可能使用的一些可能性。

首先,从语法上讲,块中的变量只在块内是已知的。在块之外,编译器(语言)已经忘记了它的全部内容。所以你可以使用这个块结构来获得一个临时变量。

编译器可以做什么?

编译器可能会计算所有块的最大存储量(即,在函数入口(函数作用域)上声明的自动变量加上最大块的大小,加上最大嵌套块的大小,...等等) 。)并在堆栈上分配该数量。当退出块时,编译器知道它的变量不再存在,并且可以为该任何后续块重用该空间(在堆栈上)。在Fortran中,这称为叠加,它与C中的并集相似。

同样可行,编译器可能在进入块时在堆栈上分配新空间(例如sub sp, 12),并在离开块时释放它(例如add sp, 12)。

可能还有其他我不知道的策略。

答案 2 :(得分:0)

编译器的作用将根据优化级别而有所不同,但人们会期望在最高优化级别,现代编译器会在x的寄存器中执行所有操作,因为它是常量1我们可以从this godbolt session gcc那里看到:

test:
    testl   %edi, %edi
    jne .L4
    rep ret
.L4:
    leal    1(%rdi), %esi
    xorl    %eax, %eax
    movl    $.LC0, %edi
    jmp printf

在最低优化级别,我们不期待任何聪明的事情,在这种情况下,gcc会为xy分配,而不会检查实际是否需要x

subq    $32, %rsp