循环内部的变量声明

3
我有一个函数,它在循环内对数组执行一些操作。每次迭代结束后,它应该将数组初始化为零。那么以下哪个选项将带来性能优势?
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 中,数组在循环内部声明并初始化为零。


1
one.c是更好的选择。在这个文件中,相同的变量内存被设置和取消,但是在two.c中,你正在创建一个循环时间buf - Rustam
memset是一个更好的选择,因为它在string.h库中具有预定义的行为,可以将整个内存块重置为零,而在循环中声明堆栈变量会导致程序在每次迭代中初始化数组,这比重置内存位置更昂贵。 - Aunn Raza
1
@Rustam实际上并不是这样的。任何生产级别的编译器都会对第二个版本进行优化,使其使用相同的内存(数量)。然而,尽量减小变量的作用域通常是一个好主意,所以我会选择two.c - The Paramagnetic Croissant
2
@AunnRaza 哎呀,那完全是错误的。memset并不是魔法。它必须遍历你想要清零的所有内存。从语义上讲,它等同于重新初始化。(有可能编译器将重新初始化实现为memset,或者反之亦然)。你所说的“在每次迭代中初始化数组比重置内存位置更耗费资源”根本就没有意义。 - The Paramagnetic Croissant
@Rustam:此外,由于在one.c中变量定义中的初始化器,会有额外的4 KiB内存初始化。如果变量在one.c中没有显式初始化,则两者将等效。 - Jonathan Leffler
参见循环内的堆栈分配,该问题也涉及到一个char buf[4096];,但是没有进行任何初始化。 - Jonathan Leffler
3个回答

4

呃,我看到了很多猜测。让我们来看看:

首先,问问自己:性能真的重要吗?也就是说,

  • 你对程序进行了基准测试吗?
  • 它是否因为调用memset或初始化而变慢了?
  • 将其更改为另一种替代方案是否导致了显著的性能提升?

我猜你还没有进行基准测试,这种情况下你一定要进行测试。或者也许在这里性能并不重要,那么你应该选择风格上更优秀的代码。

然而,总的来说,有几个关于这段代码可以说的事情。请注意,这都是猜测,因为我不知道你在循环中做什么,所以无法复制你的代码并进行基准测试,但我会尝试。

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

  1. 最小化变量名称冲突或意外重用变量的概率,以及
  2. 让编译器的优化器重用它们的存储以最小化堆栈使用。

此外,今天的激进优化编译器很可能会以相同的方式处理这两个代码片段。 memset()通常是一个编译器内置函数,因此编译器了解其语义(即它用字节填充内存)。因此,如果发现通过内联调用memset()并仅发出将内存清零的代码更快,则编译器可能会将调用内联,因此没有函数调用开销。

也可以做出相反的决定:如果编译器推断出因某种原因(即减少代码大小)更好,则可以将数组的逐字节零初始化替换为调用memset(),而且通常确实会这样做。

我在一些答案/评论中读到的论点“初始化数组比重置内存位置更昂贵”简直是胡说八道——我甚至不理解“重置内存位置”的含义。在这种情况下,零初始化和memcpy(0)都会做同样的事情,而且有可能,如果启用了足够的优化,它们将编译为完全相同的机器代码。


3

这两个程序完全相同。实际上,由于它们都没有产生任何可观察的行为,因此可以将两个程序完全优化掉。

如果您的编译器(在最大优化级别下)对任何一个程序进行了不同的处理,则可以向您的编译器供应商报告,并根据您环境中的测试使用其中任何一个看起来更快的程序。

"什么更快" 没有全局答案。

示例代码链接,我添加了一些无用的内容以抑制优化- func1 func2 体看起来非常相似。


2

两个程序都使用相同大小的栈(4KB)存储缓冲区。然而,在循环中,two.c 不会调用函数,而是直接将 0 存储到 buf 中,通常使用指令 stos。因此,如果 one.c 没有充分优化,two.c 似乎具有更好的性能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接