在循环中声明变量是否有效?

时间:2013-05-26 17:05:00

标签: c++ c compiler-optimization

如果我执行以下操作之一(我认为这个问题与本问题相同)

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),或者编译器是否足够聪明,可以知道函数可能具有多少局部变量一次,然后在函数入口处为堆栈中的所有人腾出空间?

据我所知,这在理论上依赖于编译器,但我认为这样的简单事情在所有主要编译器中都很常见。如果没有,是否有人专门了解GCCVC++编译器?

4 个答案:

答案 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没有性能损失。