是否有一个版本的memset()设置一个大于1字节(char)的值?例如,假设我们有一个memset32()函数,所以使用它我们可以执行以下操作:
int32_t array[10];
memset32(array, 0xDEADBEEF, sizeof(array));
Run Code Online (Sandbox Code Playgroud)
这将在数组的所有元素中设置值0xDEADBEEF.目前在我看来,这只能通过循环来完成.
具体来说,我对64位版本的memset()感兴趣.知道这样的事吗?
moo*_*dow 31
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];
}
}
Run Code Online (Sandbox Code Playgroud)
(解释,按照注释中的要求:当你指定一个指针时,编译器假定指针与类型的自然对齐对齐;对于uint64_t,这是8个字节.memcpy()不做这样的假设.在某些硬件上未对齐访问是不可能的,因此赋值不是一个合适的解决方案,除非你知道未对齐的访问在硬件上工作很小或没有惩罚,或者知道它们永远不会发生,或者两者兼而有.编译器将替换小的memcpy()和memset() s有更合适的代码,所以它看起来并不那么可怕;但是如果你确实知道分配将始终有效并且你的分析器告诉你它更快,你可以用一个赋值替换memcpy.第二个用于()如果要填充的内存量不是64位的倍数,则存在循环.如果你知道它总是会,你可以简单地放弃那个循环.)
Ste*_*sop 10
afaik没有标准的库函数.因此,如果您正在编写可移植代码,那么您正在查看循环.
如果您正在编写非可移植代码,请检查您的编译器/平台文档,但不要屏住呼吸,因为在这里很少得到很多帮助.也许其他人会参与提供某些功能的平台示例.
您自己编写的方式取决于您是否可以在API中定义调用者保证dst指针与您的平台(或平台,如果是可移植的)上的64位写入充分对齐.在任何具有64位整数类型的平台上,malloc至少会返回适当对齐的指针.
如果你必须应对不对齐,那么你需要像moonshadow的答案.编译器可以内联/展开大小为8的memcpy(并且如果它们存在则使用32位或64位未对齐的写操作),因此代码应该非常糟糕,但我的猜测是它可能不会特殊情况对齐目标的整个功能.我很想得到纠正,但我担心自己不会被纠正.
因此,如果您知道调用者将始终为您的体系结构提供足够对齐的dst,并且长度为8字节的倍数,那么请执行一个简单的循环来编写uint64_t(或者您的64位int是什么编译器)你可能(没有承诺)最终得到更快的代码.你肯定会有更短的代码.
无论如何,如果您关心性能,那么请对其进行分析.如果速度不够快,请再次尝试进行更多优化.如果它仍然不够快,请问一个关于CPU的asm版本的问题,它不够快.memcpy/memset可以从每个平台的优化中获得巨大的性能提升.
仅供记录,以下使用memcpy(..)以下模式.假设我们想要用20个整数填充数组:
--------------------
First copy one:
N-------------------
Then copy it to the neighbour:
NN------------------
Then copy them to make four:
NNNN----------------
And so on:
NNNNNNNN------------
NNNNNNNNNNNNNNNN----
Then copy enough to fill the array:
NNNNNNNNNNNNNNNNNNNN
Run Code Online (Sandbox Code Playgroud)
这需要O(lg(num))个应用程序memcpy(..).
int *memset_int(int *ptr, int value, size_t num) {
if (num < 1) return ptr;
memcpy(ptr, &value, sizeof(int));
size_t start = 1, step = 1;
for ( ; start + step <= num; start += step, step *= 2)
memcpy(ptr + start, ptr, sizeof(int) * step);
if (start < num)
memcpy(ptr + start, ptr, sizeof(int) * (num - start));
return ptr;
}
Run Code Online (Sandbox Code Playgroud)
我认为如果memcpy(..)使用一些硬件块内存复制功能进行优化,它可能比循环更快,但事实证明,一个简单的循环比上面的-O2和-O3更快.(至少在Windows上使用MinGW GCC和我的特定硬件.)如果没有-O开关,在400 MB阵列上,上面的代码大约是等效循环的两倍,在我的机器上需要417 ms,而在优化时两者都要大约300毫秒.这意味着它需要与字节大约相同的纳秒数,并且时钟周期约为1纳秒.因此,我的机器上没有硬件块内存复制功能,或者memcpy(..)实现没有利用它.
检查您的操作系统文档以获取本地版本,然后考虑使用该循环.
编译器可能知道更多关于优化任何特定体系结构上的内存访问的知识,所以让它完成工作.
将其作为库包装并使用编译器允许的所有速度提升优化进行编译.
wmemset(3)是 memset 的宽(16 位)版本。我认为这是你在 C 中最接近的,没有循环。