是否有memset()接受大于char的整数?
是否有memset()版本设置的值大于1个字节(字符)?例如,假设我们有一个memset32()函数,因此使用它可以执行以下操作:
int32_t array[10]; memset32(array, 0xDEADBEEF, sizeof(array));
这将在数组的所有元素中设置值0xDEADBEEF。目前,在我看来,这只能通过循环来完成。
具体来说,我对64位版本的memset()感兴趣。知道那样的事吗?
解决方案
wmemset(3)是memset的宽版本(16位)。我认为这是我们使用C语言获得的最接近的结果,没有循环。
void memset64( void * dest, uint64_t value, uintptr_t size ) { uintptr_t i; for( i = 0; i < (size & (~7)); i+=8 ) { memcpy( ((char*)dest) + i, &value, 8 ); } for( ; i < size; i++ ) { ((char*)dest)[i] = ((char*)&value)[i&7]; } }
(解释,按照注释中的要求:当我们分配给指针时,编译器会假定指针与类型的自然对齐方式对齐;对于uint64_t,则为8个字节。memcpy()不作这样的假设。在某些硬件上未对齐访问是不可能的,因此分配是不适合的解决方案,除非我们知道不对齐的访问对硬件的影响很小或者没有损失,或者知道它们永远不会发生,或者两者并存,编译器将替换小的memcpy()s和memset()使用更合适的代码,因此看起来并不可怕;但是,如果我们确实知道可以确保分配始终有效,并且探查器告诉我们它更快,则可以将Memcpy替换为一个赋值。如果要填充的内存量不是64位的倍数,则会出现循环。如果我们知道总是如此,则可以简单地删除该循环。)
检查OS文档以获取本地版本,然后考虑仅使用循环。
编译器可能比我们更了解在任何特定体系结构上优化内存访问的知识,因此让它来完成工作。
将其包装为库,并使用编译器允许的所有提高速度的优化对其进行编译。
自己写;即使在asm中也是微不足道的。
确实应该让编译器按照其他人的建议为我们优化此过程。在大多数情况下,该循环可以忽略不计。
但是,如果出现这种特殊情况,并且我们不介意特定于平台,并且确实需要摆脱循环,则可以在组装块中执行此操作。
//pseudo code asm { rep stosq ... }
我们可能可以使用google stosq汇编命令获取详细信息。它不应超过几行代码。
没有标准库函数afaik。因此,如果我们正在编写可移植的代码,那么我们就在看一个循环。
如果我们正在编写不可移植的代码,请查阅编译器/平台文档,但是请不要屏住呼吸,因为在这里很少能获得太多帮助。也许其他人会提供确实可以提供帮助的平台示例。
编写自己的方式取决于我们是否可以在API中定义调用方,以确保dst指针能够针对平台(或者平台(如果是可移植的话))上的64位写入充分对齐。在完全具有64位整数类型的任何平台上,malloc至少将返回适当对齐的指针。
如果必须应对不结盟,那么我们需要像月影影子的答案那样的东西。编译器可以内联/展开大小为8的memcpy(并使用32或者64位未对齐的写操作(如果存在)),因此代码应该相当简洁,但是我猜想它可能不会对整个情况都做特例对齐目标的功能。我希望得到纠正,但担心我不会得到纠正。
因此,如果我们知道调用方将始终为我们提供一个具有与体系结构足够对齐的dst,并且长度是8字节的倍数,那么请执行一个简单的循环,编写uint64_t(或者64位int编译器),我们可能(毫无希望)以更快的代码告终。我们肯定会拥有较短的代码。
无论如何,如果我们确实关心性能,请对其进行概要分析。如果速度不够快,请尝试进一步优化。如果仍然不够快,请询问有关其不够快的CPU的asm版本的问题。 memcpy / memset可以从每个平台的优化中获得巨大的性能提升。