memset()比C中的循环效率更高吗?

Dav*_*vid 34 c performance memset

memset比for循环更有效.所以,如果我有

char x[500];
memset(x,0,sizeof(x));
Run Code Online (Sandbox Code Playgroud)

要么

char x[500];
for(int i = 0 ; i < 500 ; i ++) x[i] = 0;
Run Code Online (Sandbox Code Playgroud)

哪一个更有效率,为什么?是否在硬件中有任何特殊指令来进行块级初始化.

Ed *_* S. 31

那么,为什么我们不看看VS 2010下生成的汇编代码,完全优化.

char x[500];
char y[500];
int i;      

memset(x, 0, sizeof(x) );   
  003A1014  push        1F4h  
  003A1019  lea         eax,[ebp-1F8h]  
  003A101F  push        0  
  003A1021  push        eax  
  003A1022  call        memset (3A1844h)  
Run Code Online (Sandbox Code Playgroud)

你的循环......

char x[500];
char y[500];
int i;    

for( i = 0; i < 500; ++i )
{
    x[i] = 0;

      00E81014  push        1F4h  
      00E81019  lea         eax,[ebp-1F8h]  
      00E8101F  push        0  
      00E81021  push        eax  
      00E81022  call        memset (0E81844h)  

      /* note that this is *replacing* the loop, 
         not being called once for each iteration. */
}
Run Code Online (Sandbox Code Playgroud)

因此,在此编译器下,生成的代码完全相同. memset很快,编译器很聪明,知道你做的事情和调用一样memset,所以它会为你做.

如果编译器实际上按原样离开了循环,那么它可能会慢一些,因为你可以一次设置多个字节大小的块(也就是说,你可以将循环展开到最小.你可以假设memset它将在至少和循环的简单实现一样快.在调试版本下尝试它,你会注意到循环没有被替换.

也就是说,这取决于编译器为您做什么.查看反汇编始终是确切知道发生了什么的好方法.


Die*_*lla 26

最肯定的是,它memset会比那个循环快得多.请注意您一次如何处理一个字符,但这些功能经过优化,一次设置几个字节,即使使用MMX和SSE指令也是如此.

我认为这些优化的典型例子,通常不被注意,是GNU C库strlen函数.人们会认为它至少具有O(n)性能,但它实际上具有O(n/4)或O(n/8),具体取决于体系结构(是的,我知道,在大O()中将是相同的,但你实际上得到了八分之一的时间).怎么样?棘手,但很好:strlen.

  • 任何优化编译器都会用最佳序列(可能是对memset的调用)替换for循环. (3认同)
  • @Stephen佳能:嘿.我正在使用clang/LLVM编译一个C库,它通过调用memset替换了库的memset for循环.哎呀!深度递归. (2认同)
  • @Richard Pennington:`-fno-builtin-memset`. (2认同)

Mic*_*ael 12

它真的取决于编译器和库.对于较旧的编译器或简单编译器,memset可能在库中实现,并且不会比自定义循环执行得更好.

对于几乎所有值得使用的编译器,memset是一个内部函数,编译器将为它生成优化的内联代码.

其他人建议进行剖析和比较,但我不打扰.只需使用memset.代码简单易懂.在您的基准测试告诉您这部分代码是性能热点之前,请不要担心.


Bob*_*ers 8

答案是"这取决于". memset可能更高效,或者它可能在内部使用for循环.我想不出一个memset效率会降低的情况.在这种情况下,它可能会变成一个更有效的for循环:你的循环迭代500次,每次将数组的字节值设置为0.在64位机器上,你可以循环,一次设置8个字节(一个很长的长),这几乎要快8倍,并且最后只处理剩下的4个字节(500%8).

编辑:

事实上,这就是memsetglibc中的内容:

http://repo.or.cz/w/glibc.git/blob/HEAD:/string/memset.c

正如Michael指出的那样,在某些情况下(编译时已知数组长度),C编译器可以内联memset,摆脱函数调用的开销.Glibc还memset为大多数主要平台提供了程序集优化版本,例如amd64:

http://repo.or.cz/w/glibc.git/blob/HEAD:/sysdeps/x86_64/memset.S