清除一个小整数数组:memset与for循环

时间:2009-07-15 21:09:22

标签: c performance benchmarking

有两种方法可以将整数/浮点数组清零:

memset(array, 0, sizeof(int)*arraysize);

或:

for (int i=0; i <arraysize; ++i)
    array[i]=0;
显然,对于大型arraysize,memset更快。但是,在什么时候memset的开销实际上大于for循环的开销?例如,对于大小为5的数组 - 哪个最好?第一个,第二个,甚至可能是未展开的版本:

array[0] = 0;
array[1] = 0;
array[2] = 0;
array[3] = 0;
array[4] = 0;

4 个答案:

答案 0 :(得分:45)

很可能,memset()将由编译器内联(大多数编译器将其视为'内在',这基本上意味着它是内联的,除非可能是最低优化或除非明确禁用)。

例如,这里有一些release notes from GCC 4.3

  

块移动的代码生成   (memcpy)和块集(memset)   被改写了。海湾合作委员会现在可以选择   最佳算法(循环,展开循环,   带有rep前缀或a的指令   库调用)基于的大小   被复制的块和CPU正在   优化的。一个新选择   -minline-stringops-dynamically有   已被添加。使用此选项字符串   未知大小的操作是   扩大了这样的小块   由内联代码复制,而for   大块使用库调用。   这导致代码比   -minline-all-stringops当   库实现是有能力的   使用缓存层次结构提示。该   启发式选择特定的   算法可以通过覆盖   -mstringop-strategy。最近也是   不同于0的memset值是   内联。

编译器可能会使用您提供的替代示例执行类似操作,但我敢打赌它不太可能。

它是grep - 能够一眼就能看出启动的目的是什么(不是说环路特别难以理解)。

答案 1 :(得分:21)

正如迈克尔已经注意到的那样,gcc和我猜其他大多数编译器已经很好地优化了这一点。例如gcc将其转为

char arr[5];
memset(arr, 0, sizeof arr);

movl  $0x0, <arr+0x0>
movb  $0x0, <arr+0x4>

它没有比那更好......

答案 2 :(得分:8)

没有测量就无法回答这个问题。它完全取决于编译器,cpu和运行时库实现。

memset()可能有点“代码味道”,因为它可能容易出现缓冲区溢出,参数反转,并且具有仅清除“逐字节”的不幸能力。然而,可以肯定的是,除了极端情况外,它将“最快”。

我倾向于使用宏来包装它以避免一些问题:

#define CLEAR(s) memset(&(s), 0, sizeof(s))

这可以避开尺寸计算并消除交换长度和值的参数问题。

简而言之,使用memset()“引擎盖下”。写下你想要的,让编译器担心优化。大多数人都非常擅长。

答案 3 :(得分:1)

考虑到这个代码本身就已经被告知了。但是如果你在它的程序中考虑它,我不知道什么,可以做其他事情。例如,如果要每隔一段时间执行此代码以清除数组,则可以运行一个线程,该线程不断地分配一个新的零元素数组,该元素分配给全局变量,当需要清除数组时,代码就是你的代码,只是指向。

这是第三种选择。当然,如果您计划在具有至少两个内核的处理器上运行代码,这是有道理的。此外,代码必须运行多次才能看到好处。对于一次性运行,您可以声明一个填充零的数组,然后在需要时指向它。

希望这可以帮助某人