我很好奇在类似于下面的情况下使用 memset() 在效率方面是否有任何优势。
给定以下缓冲区声明...
struct More_Buffer_Info
{
unsigned char a[10];
unsigned char b[10];
unsigned char c[10];
};
struct My_Buffer_Type
{
struct More_Buffer_Info buffer_info[100];
};
struct My_Buffer_Type my_buffer[5];
unsigned char *p;
p = (unsigned char *)my_buffer;
除了减少代码行数之外,使用它还有一个优势:
memset((void *)p, 0, sizeof(my_buffer));
关于这个:
for (i = 0; i < sizeof(my_buffer); i++)
{
*p++ = 0;
}
最佳答案
这适用于 memset()
和 memcpy()
:
- 更少的代码:正如您已经提到的,它更短 - 更少的代码行。
- 更具可读性:越短通常也越可读。 (
memset()
比那个循环更具可读性) - 它可以更快:它有时可以允许更积极的编译器优化。 (所以它可能会更快)
- 未对齐:在某些情况下,当您在不支持未对齐访问的处理器上处理未对齐数据时,
memset()
和memcpy ()
可能是唯一干净的解决方案。
为了扩展第三点,编译器可以使用 SIMD 等对 memset()
进行大量优化。如果您改为编写循环,编译器将首先需要“弄清楚”它的作用,然后才能尝试对其进行优化。
这里的基本思想是 memset()
和类似的库函数,在某种意义上,“告诉”编译器你的意图。
正如@Oli 在评论中提到的,有一些缺点。我将在这里展开它们:
- 您需要确保
memset()
确实按照您的要求执行。该标准并未说明各种数据类型的零在内存中必须为零。 - 对于非零数据,
memset()
仅限于 1 个字节的内容。因此,如果您想将int
数组设置为零以外的值(或0x01010101
或其他值),则不能使用memset()
...)。 - 虽然很少见,但在某些极端情况下,您实际上可以使用自己的循环在性能上击败编译器。*
*我将根据我的经验举一个例子:
尽管 memset()
和 memcpy()
通常是编译器内部函数,由编译器进行特殊处理,但它们仍然是 generic 函数。他们只字不提数据类型,包括数据的对齐方式。
因此在少数情况下(虽然很少见),编译器无法确定内存区域的对齐方式,因此必须生成额外的代码来处理未对齐情况。然而,如果您是程序员,100% 确定对齐,那么使用循环实际上可能会更快。
一个常见的例子是使用 SSE/AVX 内在函数。 (例如复制 16/32 字节对齐的 float
数组)如果编译器无法确定 16/32 字节对齐,则需要使用未对齐的加载/存储和/或处理代码。如果您只是使用 SSE/AVX 对齐的加载/存储内在函数编写一个循环,您可能会做得更好。
float *ptrA = ... // some unknown source, guaranteed to be 32-byte aligned
float *ptrB = ... // some unknown source, guaranteed to be 32-byte aligned
int length = ... // some unknown source, guaranteed to be multiple of 8
// memcopy() - Compiler can't read comments. It doesn't know the data is 32-byte
// aligned. So it may generate unnecessary misalignment handling code.
memcpy(ptrA, ptrB, length * sizeof(float));
// This loop could potentially be faster because it "uses" the fact that
// the pointers are aligned. The compiler can also further optimize this.
for (int c = 0; c < length; c += 8){
_mm256_store_ps(ptrA + c, _mm256_load_ps(ptrB + c));
}
关于c - 在 C 中使用 memset() 有什么好处,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8528590/