循环内的变量声明

时间:2014-10-24 04:34:14

标签: c performance loops

我有一个函数在内部循环的数组上做一些操作。在每次迭代之后,它应该将数组初始化为零。那么以下哪项会带来性能优势?

one.c

int main(void){
 char buf[4096] = { 0};

 while (1 /*flag*/) {

       /*Some operation here*/
    memset (buf, 0, sizeof (buf));
    }
}

two.c

int main(void){

 while (1 /*flag*/) {
       char buf[4096] = { 0};
       /*Some operation here*/
    }
}

在one.c中使用显式memset。但在two.c数组中,在循环内声明并初始化为零。

3 个答案:

答案 0 :(得分:4)

唉。我看到很多猜测都在继续。我们来看看:

首先,问问自己:性能是否重要? IOW,

  • 你有基准程序吗?
  • 因为调用memset或初始化而变得很慢?
  • 确实将其改为其他替代结果,显着改善了性能?

我猜你还没有基准测试,在这种情况下你肯定应该。或者也许性能在这里并不重要,在这种情况下你应该选择风格优越的。

但是,一般情况下,关于此代码可以说几件事。请注意这是所有推测,,因为我不知道你在循环中做了什么,因此无法重现你的代码并对其进行基准测试,但我愿意。

首先,我更喜欢第二个版本,因为它最小化了缓冲区的范围。通常,您希望最小化变量的生命周期,以便:

  1. 最小化变量名称冲突或意外重复使用变量的概率,
  2. 让编译器的优化器将其存储重用于其他变量,以最大限度地减少堆栈使用。
  3. 此外,今天积极优化的编译器很可能会同样对待这两段代码。 memset()通常是编译器内部函数,因此编译器知道它的语义(即它用字节填充内存)。因此,编译器可能会内联对memset()的调用,并且只发出将内存清零的代码,如果事实证明这样做更快,那么就没有函数调用开销。

    也可以做出相反的决定:如果编译器推断出由于某种原因(即减小代码大小)调用函数更好,那么它可以将数组的逐字节零初始化替换为memset()的号召,通常确实如此。

    我在一些答案/评论中读到的论点“初始化阵列比重置内存位置更昂贵”简直是胡说八道 - 我甚至不明白“重置内存位置”是什么意思。零初始化和memcpy(0)在这种情况下都做同样的事情,如果你在启用了足够的优化的情况下进行编译,它们将编译成完全相同的机器代码。

答案 1 :(得分:3)

这些都完全一样。实际上,两个程序都可以完全优化,因为没有任何程序可以产生任何可观察的行为。

如果您的编译器(在最大优化级别)对任一程序执行不同的操作,那么可以将其报告给编译器供应商,并且还可以根据您环境中的测试使用哪一个似乎更快。

“什么是更快”没有全球答案。

Link to example code我添加了一些禁止优化的内容 - func1func2看起来非常相似。

答案 2 :(得分:2)

它们都使用相同大小的堆栈(4KB)来存储缓冲区,但是,在循环中,two.c不会调用函数,它直接将0存储到buf,通常使用指令stos,因此,如果one.c未充分优化,two.c似乎有更好的效果。