Как memset() память для определенного шаблона вместо одного байта?

Сегодня я столкнулся с проблемой, когда мне нужно изменить память на определенный шаблон, такой как 0x 11223344, чтобы вся память выглядела (в шестнадцатеричной форме):

1122334411223344112233441122334411223344112233441122334411223344...

Я не могу понять, как это сделать с memset(), потому что он принимает только один байт, а не 4 байта.

Любые идеи?

Спасибо, Бода Сидо.

Ответ 1

Эффективным способом было бы указать указатель на нужный размер в байтах (например, 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;
}

Не тестировалось!

Ответ 2

В OS X для этого используется memset_pattern4( ); Я ожидаю, что другие платформы будут иметь аналогичные API.

Я не знаю простого портативного решения, отличного от заполнения буфера контуром (который довольно прост).

Ответ 3

Рекурсивно скопируйте память, используя область, которую вы уже заполнили в качестве шаблона на итерацию (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);

[EDIT] Что я имею в виду под "O (log (N))", так это то, что время выполнения будет намного быстрее, чем если вы будете заполнять память вручную, поскольку memmove() обычно использует специальные, оптимизированные вручную петли ассемблера, которые пылают быстро.

Ответ 4

Вы можете настроить последовательность где-то, а затем скопировать ее с помощью memcpy() туда, где вам это нужно.

Ответ 5

Если ваш шаблон соответствует wchar_t, вы можете использовать wmemset(), как вы бы использовали memset().

Ответ 6

Ну, нормальный способ сделать это - вручную настроить первые четыре байта, а затем memcpy(ptr+4, ptr, len -4)

Это копирует первые четыре байта во второй четыре байта, затем копирует второй четыре байта в третий и т.д.

Обратите внимание, что это "обычно" работает, но не гарантируется в зависимости от вашей архитектуры процессора и библиотеки времени выполнения C.

Ответ 7

Использование "memcpy" или "memset" может быть не эффективным методом.

Не отказываться от использования циклов, таких как "для" или "пока", когда функция, определяемая lib, делает то же самое.

Ответ 8

Стандартная библиотека 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
}

Хороший компилятор, вероятно, будет использовать некоторые специфичные для процессора инструкции для дальнейшей его оптимизации (например, использовать 128-битное хранилище SSE), но даже без оптимизации он должен быть таким же быстрым, как библиотека memset, поскольку такие простые циклы привязаны к доступу к памяти ,