我有一个函数在内部循环的数组上做一些操作。在每次迭代之后,它应该将数组初始化为零。那么以下哪项会带来性能优势?
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数组中,在循环内声明并初始化为零。
答案 0 :(得分:4)
唉。我看到很多猜测都在继续。我们来看看:
首先,问问自己:性能是否重要? IOW,
我猜你还没有基准测试,在这种情况下你肯定应该。或者也许性能在这里并不重要,在这种情况下你应该选择风格优越的。
但是,一般情况下,关于此代码可以说几件事。请注意这是所有推测,,因为我不知道你在循环中做了什么,因此无法重现你的代码并对其进行基准测试,但我愿意。
首先,我更喜欢第二个版本,因为它最小化了缓冲区的范围。通常,您希望最小化变量的生命周期,以便:
此外,今天积极优化的编译器很可能会同样对待这两段代码。 memset()
通常是编译器内部函数,因此编译器知道它的语义(即它用字节填充内存)。因此,编译器可能会内联对memset()
的调用,并且只发出将内存清零的代码,如果事实证明这样做更快,那么就没有函数调用开销。
也可以做出相反的决定:如果编译器推断出由于某种原因(即减小代码大小)调用函数更好,那么它可以将数组的逐字节零初始化替换为memset()
的号召,通常确实如此。
我在一些答案/评论中读到的论点“初始化阵列比重置内存位置更昂贵”简直是胡说八道 - 我甚至不明白“重置内存位置”是什么意思。零初始化和memcpy(0)
在这种情况下都做同样的事情,如果你在启用了足够的优化的情况下进行编译,它们将编译成完全相同的机器代码。
答案 1 :(得分:3)
这些都完全一样。实际上,两个程序都可以完全优化,因为没有任何程序可以产生任何可观察的行为。
如果您的编译器(在最大优化级别)对任一程序执行不同的操作,那么可以将其报告给编译器供应商,并且还可以根据您环境中的测试使用哪一个似乎更快。
“什么是更快”没有全球答案。
Link to example code我添加了一些禁止优化的内容 - func1
和func2
看起来非常相似。
答案 2 :(得分:2)
它们都使用相同大小的堆栈(4KB)来存储缓冲区,但是,在循环中,two.c
不会调用函数,它直接将0存储到buf
,通常使用指令stos
,因此,如果one.c
未充分优化,two.c
似乎有更好的效果。