是否有用于 16 和/或 32 位值的 memset() 函数?
Posted
技术标签:
【中文标题】是否有用于 16 和/或 32 位值的 memset() 函数?【英文标题】:Is there a memset() function for 16 and/or 32 bit values? 【发布时间】:2019-04-19 14:05:06 【问题描述】:memset()
非常快,因为它在内部受益于stosb
操作码。
是否有适用于 16 位和 32 位值的函数,可以有效地受益于 stosb
、stosw
和/或 stosd
?
wmemset()
不可移植,对 16 位值没有帮助。
【问题讨论】:
它适用于 256 个不同的 16 位和 32 位值,其中每个组件字节都具有相同的值,例如0
和 -1
(如果是二进制补码)。
stosw
和 stosd
与 stosb
不同。在过去,所有这些指令都非常非常慢,因为它们在 uCode 级别上得到支持,并且为了向后兼容而保留。后来 Intel CPU 开始在硬件中实现stosb
,以在硬件上提供高速memcpy
,但stosw
、stosd
保持不变——基于uCode,因此非常慢。我认为没有任何变化,但我没有真正检查。
C++ 有::std::fill
编译器通常会以这种方式优化。
不幸的是我不能在我的项目中使用 C++ 函数。
你也可以阅读this关于stosb
和stosw
/stosd
之间区别的问题。这是我在之前的评论中谈到的。
【参考方案1】:
标准 C 中没有这样的功能,但根据您要执行的操作,您可能会使用特定于 CPU 的 SIMD“内在功能”来构建一个。您提到 stosb
让我觉得您使用的是 x86,因此请查看各种 *mmintrin.h
标头及其提供的功能的文档。
【讨论】:
是的,我在/usr/lib/gcc/x86_64-linux-gnu/7/include
中有这样的文件。但是我在哪里可以找到,我在寻找什么?你的意思是这样的:***.com/a/25579184/5399598 这是 32 位的。首先,我正在寻找 16 位的东西。
@CoSoCo 对不起,我已经帮不了你了。【参考方案2】:
是的,它有很多变体。
例如
void *memset16(void *m, uint16_t val, size_t count)
uint16_t *buf = m;
while(count--) *buf++ = val;
return m;
void *memset32(void *m, uint32_t val, size_t count)
uint32_t *buf = m;
while(count--) *buf++ = val;
return m;
void *memsetXX(void *m, void *val, size_t size, size_t count)
char *buf = m;
while(count--)
memcpy(buf, val, size);
buf += size;
return m;
更安全的版本:
void *memset16safe(void *m, uint16_t val, size_t count)
char *buf = m;
union
uint8_t d8[2];
uint16_t d16;
u16 = .d16 = val;
while(count--)
*buf++ = u16.d8[0];
*buf++ = u16.d8[1];
return m;
void *memset32(void *m, uint32_t val, size_t count)
char *buf = m;
union
uint8_t d8[4];
uint32_t d32;
u32 = .d32 = val;
while(count--)
*buf++ = u32.d8[0];
*buf++ = u32.d8[1];
*buf++ = u32.d8[2];
*buf++ = u32.d8[3];
return m;
【讨论】:
人们必须小心这些(至少是固定宽度的变体),因为与常规的memset
不同,存在混叠违规的可能性。如果m
参数指向的对象与uint16_t
不兼容--或使用的任何类型--将调用未定义的行为。
@ChristianGibbons 我在这里看不到别名问题。对齐是 - 在某些情况下。
@P__J__ 假设一个变量声明为float fvec[N]
,那么memset32(&fvec, 0x7fe00000, N)
具有未定义的行为,即使float
和uint32_t
具有相同的大小和对齐要求。
我不明白,为什么这些函数可以像使用普通循环一样更快,例如:uint16_t fill = pattern; for (int x=count; x >= --x; ) data[x] = fill;
它和uint8_t fill = pattern;
一样慢@ 在 8 位的情况下,我可以将其替换为非常快的 memset() 函数。但在 16 位的情况下,我错过了/不知道这么快的可能性。以上是关于是否有用于 16 和/或 32 位值的 memset() 函数?的主要内容,如果未能解决你的问题,请参考以下文章