【问题标题】:Does It Matter If I Declare A Variable Inside A Loop?如果我在循环中声明变量是否重要?
【发布时间】:2014-01-10 07:09:14
【问题描述】:

我的问题是,如果我在循环外声明一个变量并在循环内每次都重新初始化,还是在循环内声明和初始化,这有关系吗?那么这两种语法(性能、标准等)基本上有什么区别吗?

方法一

int a,count=0;
while(count<10)
   a=0;

方法二

int count=0;
while(count<10)
   int a=0;

请假设这只是一个更大程序的一部分,并且内部循环要求变量a 每次都具有0 的值。那么,这两种方法的执行时间会有什么不同吗?

【问题讨论】:

  • 在第二种情况下,您的变量 a 在循环外将不可用。
  • 不,根本不会有性能差异。
  • 可能存在性能差异,但除非您的循环运行数十亿次并且编译器很可能无论如何都会对其进行优化,否则它不会出现。不要担心小的性能问题。下面提到的范围问题要重要得多。
  • 我认为方法2只适用于C++,不适用于C
  • @SAM;如果您在 while 主体周围放置大括号,则可以在 C 中使用。

标签: c while-loop scope declaration


【解决方案1】:

是的,这很重要。第二种情况

int count=0;
while(count<10)
   int a=0;

a 不能在 while 循环之外被引用。它具有块范围;可以引用变量的程序文本部分。
Jonathan Leffler 在他的answer 中指出的另一件事是这两个循环都是无限循环。其次,最重要的第二个 sn-p 没有{}(在 C 中)就无法编译,因为变量定义/声明不是语句,不能作为循环体出现。

 int count  =0;
 while(count++ < 10)
 {  
      int a=0;  
 } 

【讨论】:

  • @Hanky웃Panky;补充说。:)
  • 请注意,变量定义/声明不是语句,不能有标签前缀或作为循环体出现。如果循环体周围有大括号,它会工作正常;大括号构成一个块,并且块内允许定义变量。
  • @JonathanLeffler;明白了。
  • @hacks - 我的基本问题仍未得到解答(尽管我也学到了其他很好的东西),问题是这两个循环之间是否会有任何PERFORMANCE 差异(说我运行了十亿次)?
  • @PranavJituri:在循环的每次迭代中将变量 a 设置为 0 会有边际成本。这是否可以衡量是值得怀疑的。这当然不是担心它的好理由。现在,如果不是一个简单的int(可能在寄存器中),而是一个包含 1000 个元素的数组,该数组具有第 37 个元素的初始化程序(因此将其他 999 个元素归零),那么就会有是一个既可衡量又值得担心的成本。
【解决方案2】:

这个

void f1(void)
{
  int a, count = 10;
  while (count--)
    a = 0;
}

void f2(void)
{
  int count = 10;
  while (count--)
  {
    int a = 0;
  }
}

结果(使用非优化 gcc (Debian 4.4.5-8) 4.4.5):

.globl f1
        .type   f1, @function
f1:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        movl    $10, -4(%rbp)
        jmp     .L2
.L3:
        movl    $0, -8(%rbp)
.L2:
        cmpl    $0, -4(%rbp)
        setne   %al
        subl    $1, -4(%rbp)
        testb   %al, %al
        jne     .L3
        leave
        ret
        .cfi_endproc
.LFE0:
        .size   f1, .-f1
.globl f2
        .type   f2, @function
f2:
.LFB1:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        movl    $10, -8(%rbp)
        jmp     .L6
.L7:
        movl    $0, -4(%rbp)
.L6:
        cmpl    $0, -8(%rbp)
        setne   %al
        subl    $1, -8(%rbp)
        testb   %al, %al
        jne     .L7
        leave
        ret
        .cfi_endproc
.LFE1:
        .size   f2, .-f2

汇编代码看起来很安静。

【讨论】:

  • 我敢打赌,如果您添加大括号,并且可能在 while 循环之外添加 printf,它看起来不会一样
  • @EliasVanOotegem:“大括号”?在哪里?围绕a = 0;?组装肯定是一样的。 printf() 打印什么和在哪里?
  • 抱歉,可能还有一点悬念……把while() a = 0;误认为while() int a = 0;没关系。不过,如果您在循环之后没有访问变量,并且函数立即返回,那么您肯定不会在 asm 中看到差异,因为函数 + 块范围同时被 GC'ed,为什么不在这两种情况下,在 while 之后添加一个赋值,看看结果 asm 是否仍然匹配
  • @EliasVanOotegem:“...添加一个作业...”给什么? a 在第二个示例中的 while-loop 之后超出范围。触摸count 并不会改变任何事情。
  • Exacyly:如果 asm 看起来相同,那是因为编译器将这两个函数翻译为相同的东西,如果在第二个示例中的 while 块之后添加对 count 的赋值,则生成的 asm 代码应该显示差异,理论上,a 应该在最后一次分配给count 之前被释放,在这种情况下
【解决方案3】:

第一次编译;第二个没有。第一个运行了很长时间。

如果第二个是:

int count = 0;
while (count++ < 10)
{
    int a = 0;
    ...do something with a...
}

并且您还进行了类似的更改并在第一个循环中对a 做了一些事情,那么不同之处在于,在第二种情况下,a 在循环的每次迭代中都设置为零,但它保持它的任何值在第一种情况下设置为在循环中。另外,在第二种情况下,变量a在循环外不存在,因此不能在循环后被引用。

【讨论】:

  • 这不是我的反对意见,但您的大部分答案似乎都集中在 OP 给出的具体(公认有缺陷)示例上,而不是更普遍的潜在问题。
  • 这些天在 SO 上有一场投票反对(没有评论)!
  • @delnan:感谢您的评论。我看到三行完整的文本解决了正确的一般案例代码,以及一个简短的行概述了所问问题中的缺陷。我不确定应该将余额更改为什么。
  • 我认为这个答案没有任何问题。我认为这是完整的答案。 +1
  • 事实上,这个答案考虑到了 OP 提供的 sn-p 中的无限循环问题。这不是错误,而是正确的。
【解决方案4】:

是的,在您的第一种方法中,下一个更大的程序为零。

而在您的方法 2 中,无法在进一步的语句中访问相同的“a”。如果是这样,将产生一个错误,因为未定义对变量“a”的引用。该循环寿命为零,但循环后什么都没有。你可以在那个while循环之后再次定义变量'a'。

【讨论】:

    猜你喜欢
    • 2018-04-25
    • 2022-11-04
    • 1970-01-01
    • 1970-01-01
    • 2015-03-25
    • 1970-01-01
    • 1970-01-01
    • 2018-04-16
    • 1970-01-01
    相关资源
    最近更新 更多