如果我执行以下操作之一(我认为这个问题与本问题相同)
for(int i=0; i<A; i++)
{
//... do stuff
for(int j=0; j<B; j++)
{
//... do stuff
}
//... do stuff
}
for(int i=0; i<A; i++)
{
int j;
//... do stuff
}
每个循环都会在堆栈上重新创建变量j
(每个循环都会不断更新SP
),或者编译器是否足够聪明,可以知道函数可能具有多少局部变量一次,然后在函数入口处为堆栈中的所有人腾出空间?
据我所知,这在理论上依赖于编译器,但我认为这样的简单事情在所有主要编译器中都很常见。如果没有,是否有人专门了解GCC
和VC++
编译器?
答案 0 :(得分:5)
效率很高。与大多数现代编译器一样,gcc
将优化它。还要记住Donald Knuth所说的话:
我们应该忘记效率低,大约97%的时间说: 过早优化是万恶之源。
您可以通过比较汇编代码来检查它是否有效。例如,使用diff
进行比较。要生成程序集,请使用-S
标记gcc -S
。它相当于gcc -S -O0
,因为默认优化级别为0.因此,即使在最低级别优化,gcc
也将为您处理此变量。
第一个版本(为了更好的可读性,更喜欢这种方式):
#include <stdio.h>
int main()
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
printf("%d ", i + j);
}
}
return 0;
}
第二版:
#include <stdio.h>
int main()
{
for (int i = 0; i < 10; i++)
{
int j;
for (j = 0; j < 10; j++)
{
printf("%d ", i + j);
}
}
return 0;
}
相同的装配结果:
.file "main.cpp"
.section .rodata
.LC0:
.string "%d "
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
subq $16, %rsp
movl $0, -4(%rbp)
jmp .L2
.L5:
movl $0, -8(%rbp)
jmp .L3
.L4:
movl -8(%rbp), %eax
movl -4(%rbp), %edx
leal (%rdx,%rax), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
addl $1, -8(%rbp)
.L3:
cmpl $9, -8(%rbp)
setle %al
testb %al, %al
jne .L4
addl $1, -4(%rbp)
.L2:
cmpl $9, -4(%rbp)
setle %al
testb %al, %al
jne .L5
movl $0, %eax
leave
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"
.section .note.GNU-stack,"",@progbits
int i
为-4(%rbp)
,int j
为-8(%rbp)
。如您所见,int j
未重新分配或其他内容。
答案 1 :(得分:2)
我相信变量只会创建一次,虽然我不在乎,我也不相信你应该。
这可能是您的预优化(或不必要的优化)的一个例子;通过在循环中声明变量而产生的潜在低效率非常小,并且“#34;优化&#34;通过在不同位置声明变量,您的代码对程序的整体运行时和内存使用量的影响可以忽略不计。
考虑花时间优化算法并找到有效的数据结构,因为这可能会更好地利用您的时间。
答案 2 :(得分:0)
今天编译器太强大了,无法优化这些东西。因此,请不要因为您的方便而烦恼和使用。过早优化更加邪恶。
答案 3 :(得分:0)
为什么不亲自尝试看看?
class foo {
public:
foo () { std::cout << "Construct\n"; }
~foo () { std::cout << "Destruct\n"; }
};
int main () {
for ( int i = 0; i < 10; ++i ) {
foo f;
}
return 0;
}
每次循环时都会看到f
的构造函数(和析构函数!)被调用。因此,您的问题的答案是“是的,每次循环都会重新创建变量。”
回到你的例子,你声明一个int,它有一个什么都不做的构造函数和析构函数。因此,在循环中声明一个int没有性能损失。