【问题标题】:Is there a memset() function for 16 and/or 32 bit values?是否有用于 16 和/或 32 位值的 memset() 函数?
【发布时间】:2019-04-19 14:05:06
【问题描述】:

memset() 非常快,因为它在内部受益于stosb 操作码。 是否有适用于 16 位和 32 位值的函数,可以有效地受益于 stosbstosw 和/或 stosd

wmemset() 不可移植,对 16 位值没有帮助。

【问题讨论】:

  • 它适用于 256 个不同的 16 位和 32 位值,其中每个组件字节都具有相同的值,例如 0-1(如果是二进制补码)。
  • stoswstosdstosb 不同。在过去,所有这些指令都非常非常慢,因为它们在 uCode 级别上得到支持,并且为了向后兼容而保留。后来 Intel CPU 开始在硬件中实现stosb,以在硬件上提供高速memcpy,但stoswstosd 保持不变——基于uCode,因此非常慢。我认为没有任何变化,但我没有真正检查。
  • C++ 有::std::fill 编译器通常会以这种方式优化。
  • 不幸的是我不能在我的项目中使用 C++ 函数。
  • 你也可以阅读this关于stosbstosw/stosd之间区别的问题。这是我在之前的评论中谈到的。

标签: c memset


【解决方案1】:

标准 C 中没有这样的功能,但根据您要执行的操作,您可能会使用特定于 CPU 的 SIMD“内在功能”来构建一个。您提到 stosb 让我觉得您使用的是 x86,因此请查看各种 *mmintrin.h 标头及其提供的功能的文档。

【讨论】:

  • 是的,我在/usr/lib/gcc/x86_64-linux-gnu/7/include 中有这样的文件。但是我在哪里可以找到,我在寻找什么?你的意思是这样的:stackoverflow.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) 具有未定义的行为,即使floatuint32_t 具有相同的大小和对齐要求。
  • 我不明白,为什么这些函数可以像使用普通循环一样更快,例如:uint16_t fill = pattern; for (int x=count; x >= --x; ) data[x] = fill; 它和uint8_t fill = pattern; 一样慢@ 在 8 位的情况下,我可以将其替换为非常快的 memset() 函数。但在 16 位的情况下,我错过了/不知道这么快的可能性。
猜你喜欢
  • 1970-01-01
  • 2023-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多