C语言 如何将memset()内存设置为某种模式而不是单个字节?

frebpwbc  于 2022-12-03  发布在  其他
关注(0)|答案(8)|浏览(111)

我需要将一个重复的模式写入内存(例如0x11223344),这样整个内存看起来就像(十六进制):

1122334411223344112233441122334411223344112233441122334411223344...

我不知道如何使用memset(),因为它只需要一个字节,而不是4个字节。
有什么想法吗?

0dxa2lsx

0dxa2lsx1#

在OS X上,可以使用memset_pattern4( );我希望其他平台也有类似的API。
除了用循环填充缓冲区(非常简单)之外,我不知道还有什么简单的可移植解决方案。

um6iljoc

um6iljoc2#

递归地复制内存,使用你已经填充的区域作为模板,每次迭代O(log(N)):

int fillLen = ...;
int blockSize = 4; // Size of your pattern

memmove(dest, srcPattern, blockSize);
char * start = dest;
char * current = dest + blockSize;
char * end = start + fillLen;
while(current + blockSize < end) {
    memmove(current, start, blockSize);
    current += blockSize;
    blockSize *= 2;
}
// fill the rest
memmove(current, start, (int)end-current);

我的意思是O(log(N))的运行时间将比手动填充内存快得多,因为memmove()通常使用特殊的、手动优化的汇编循环,速度非常快。

bq8i3lrv

bq8i3lrv3#

一种有效的方法是将指针转换为所需字节大小的指针(例如uint32_t为4字节),然后用整数填充。

char buf[256] = { 0, };
uint32_t * p = (uint32_t *) buf, i;

for (i = 0; i < sizeof(buf) / sizeof(* p); i++) {
    p[i] = 0x11223344;
}

未测试!

bis0qfac

bis0qfac4#

如果您的模式适合wchar_t,则可以像使用memset()一样使用wmemset()

8yoxcaq7

8yoxcaq75#

正常的方法是手动设置前四个字节,然后设置memcpy(ptr+4, ptr, len -4)
这会将前四个字节复制到后四个字节,然后将后四个字节复制到第三个字节,依此类推。
请注意,这“通常”是可行的,但不保证一定可行,具体取决于您的CPU体系结构和C运行时库。

wecizke3

wecizke36#

您可以在某处设置序列,然后使用memcpy()将其复制到所需位置。

58wvjzkj

58wvjzkj7#

标准C库没有这样的函数。但是memset通常被实现为一个展开的循环,以最小化分支和条件检查:

static INLINE void memset4(uint32_t *RESTRICT p, uint32_t val, int len) {
  uint32_t *end = p + (len&~0x1f); //round down to nearest multiple of 32
  while (p != end) { //copy 32 times
    p[ 0] = val;
    p[ 1] = val;
    p[ 2] = val;
    p[ 3] = val;
    p[ 4] = val;
    p[ 5] = val;
    p[ 6] = val;
    p[ 7] = val;
    p[ 8] = val;
    p[ 9] = val;
    p[10] = val;
    p[11] = val;
    p[12] = val;
    p[13] = val;
    p[14] = val;
    p[15] = val;
    p[16] = val;
    p[17] = val;
    p[18] = val;
    p[19] = val;
    p[20] = val;
    p[21] = val;
    p[22] = val;
    p[23] = val;
    p[24] = val;
    p[25] = val;
    p[26] = val;
    p[27] = val;
    p[28] = val;
    p[29] = val;
    p[30] = val;
    p[31] = val;
    p += 32;
  }
  end += len&0x1f; //remained
  while (p != end) *p++ = val; //copy remaining bytes
}

好的编译器可能会使用一些特定于CPU的指令来进一步优化它(例如,使用SSE 128位存储),但即使没有优化,它也应该与库memset一样快,因为这样的简单循环是内存访问绑定的。

pgccezyw

pgccezyw8#

今天,当我不得不在内存对齐数组中复制一个复杂的标量,以便使用Volk执行SIMD乘法时,我就在考虑这个问题。我看到了上面的解决方案,但我对编译器的了解还不足以说明哪些可以优化,哪些不可以优化。我计划对其中的一些建议进行基准测试,但我想到的解决方案是:

inline void duplicate_32fc(lv_32fc_t *out, lv_32fc_t in, int size) {

    int n = 1;
    int last_n;

    if (n < 1)
        return;

    //Copy the first one
    out[0] = in;

    //Double the size of the copy for each copy
    while (n*2 <= size) {
        memcpy(&out[n], out, n * sizeof(lv_32fc_t));
        last_n = n;
        n = n * 2;
    }

    //Copy the tail
    if (last_n < size) {
        memcpy(&out[last_n], out, (size - last_n) * sizeof(lv_32fc_t));
    }
}

每次迭代都会把之前的所有副本复制到新的空间,所以我认为这是O(log(n)),不是吗?

相关问题