我对这样的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
变量必须存在于内存中。
现代编译器使用这种技术吗?
答案 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会为x
和y
分配,而不会检查实际是否需要x
:
subq $32, %rsp