Как я могу скопировать повторяющийся шаблон в буфер памяти? - PullRequest
6 голосов
/ 13 июня 2011

Я хочу записать повторяющуюся последовательность байтов в блок памяти. Моя идея состоит в том, чтобы написать первый пример шаблона, а затем скопировать его в оставшуюся часть буфера. Например, если я начну с этого:

ptr: 123400000000

Впоследствии я хочу, чтобы это выглядело так:

ptr: 123412341234

Я думал, что смогу использовать memcpy для записи в пересекающиеся области, например:

memcpy(ptr + 4, ptr, 8);

Стандарт не указывает, в каком порядке будет происходить копирование, поэтому, если какая-то реализация делает его копирование в обратном порядке, это может дать разные результаты:

ptr: 123412340000

или даже объединенные результаты.

Есть ли обходной путь, который позволяет мне все еще использовать memcpy, или я должен реализовать свой собственный цикл for? Обратите внимание, что я не могу использовать memmove, потому что он делает именно то, что я пытаюсь избежать; это делает ptr 123412340000, а я хочу 123412341234.

Я программирую для Mac / iPhone (clang compiler), но общий ответ тоже будет хорош.

Ответы [ 6 ]

5 голосов
/ 13 июня 2011

Нет стандартной функции для повторения последовательности байтов в диапазоне памяти. Вы можете использовать семейство функций memset_pattern* для получения шаблонов фиксированного размера; если вам нужно изменить размер, вам придется свернуть свой собственный.

// fills the 12 first bytes at `ptr` with the 4 first bytes of `ptr`
memset_pattern4(ptr, ptr, 12);

Имейте в виду, что memset_pattern4, memset_pattern8 и memset_pattern16 существуют только в Mac OS / iOS, поэтому не используйте их для кроссплатформенной разработки.

В противном случае, кроссплатформенная функция, которая выполняет побайтное копирование, довольно проста.

void byte_copy(void* into, void* from, size_t size)
{
    for (size_t i = 0; i < size; i++)
        into[i] = from[i];
}
5 голосов
/ 13 июня 2011

Вот что говорит kernel.org :

Функция memcpy () копирует n байтов из области памяти src в область памяти Dest. Области памяти не должны перекрываться . Используйте memmove (3), если области памяти перекрываются.

Вот что говорит MSDN :

Если источник и пункт назначения перекрываются, поведение memcpy не определено . Используйте memmove для обработки перекрытия регионы.

2 голосов
/ 03 июня 2015

Ответ C ++ для всех платформ: std :: fill_n (destination, elementRepeats, elementValue).

Для того, что вы просили:

short val = 0x1234;
std::fill_n(ptr, 3, val); 

Это будет работать для valлюбого типа;символы, шорты, целые, int64_t и т. д.

0 голосов
/ 30 мая 2017

Вы можете сделать это, скопировав один раз, а затем memcpy все скопировать в следующие байты и повторить, это лучше понять в коде:

void block_memset(void *destination, const void *source, size_t source_size, size_t repeats) {
    memcpy(destination,source,source_size);
    for (size_t i = 1; i < repeats; i += i)
        memcpy(destination + i,destination,source_size * (min(i,repeats - i)));
}

Я тестировал; это просто как обычный memset для большого числа repeats, и source_size довольно динамичен без большого снижения производительности тоже.

0 голосов
/ 13 июня 2011

Старый ответ

Вы хотите memmove().Полное описание:

Функция memmove () должна копировать n байтов из объекта, на который указывает s2, в объект, на который указывает s1.Копирование происходит так, как будто n байтов из объекта, на который указывает s2, сначала копируются во временный массив из n байтов, который не перекрывает объекты, на которые указывают s1 и s2, а затем n байтов из временного массива копируются вобъект, на который указывает s1.

со страницы memcpy():

Если копирование происходит между перекрывающимися объектами, поведениене определено.

Вы все равно должны использовать memmove().Это потому, что результат использования memcpy() не является надежным в любом случае.

Соответствующие биты для фактического вопроса

Вы спрашиваете memcpy(ptr + 4, ptr, 8);, который говорит, что скопируйте 8 байтов из ptr и поместите их в ptr+4.ptr - 123400000000, первые 8 байтов - 1234000, поэтому он делает это:

Original : 123400000000
Writes   :     12340000
Result   : 123412340000

Вам нужно позвонить:

memcpy(ptr+4, ptr, 4);
memcpy(ptr+8, ptr, 4);

Чтобы достичь того, что выпосле.Или реализовать эквивалент.Это должно сделать это, но это не проверено и эквивалентно memcpy;вам нужно будет либо добавить дополнительный временный буфер, либо использовать две непересекающиеся области памяти.

void memexpand(void* result, const void* start, 
               const uint64_t cycle, const uint64_t limit)
{
    uint64_t count = 0;
    uint8_t* source = start;
    uint8_t* dest   = result;

    while ( count < limit )
    {
        *dest = *source;
        dest++;
        count++;

        if ( count % cycle == 0 )
        {
            source = start;
        }
        else
        {
            source++;
        }
    }
}
0 голосов
/ 13 июня 2011

Почему бы просто не выделить 8-байтовый буфер, переместить его туда, а затем переместить обратно туда, куда вы хотите? (Как говорит @cnicutar, у вас не должно быть перекрывающихся адресных пространств для memcpy.)

...