C memcpy в обратном порядке

Я работаю со звуковыми данными. Я хотел бы воспроизвести образец файла в обратном порядке. Данные хранятся как беззнаковые целые и упакованы хорошо и плотно. Есть ли способ вызвать memcpy, который будет копировать в обратном порядке. т. е. если бы у меня было 1,2,3,4, хранящихся в массиве, мог бы я вызвать memcpy и волшебным образом поменять их местами, чтобы получить 4,3,2,1.


person Aran Mulholland    schedule 11.02.2010    source источник
comment
В C нет такой функции, но ее очень легко написать.   -  person Alok Singhal    schedule 11.02.2010
comment
Возможно, стоит подумать об изменении того, как вы перебираете данные, а не об изменении порядка, я подозреваю, что это было бы более эффективно...   -  person Mark Elliot    schedule 11.02.2010
comment
Вы поставили меня в тупик волшебным образом.   -  person Craig McQueen    schedule 11.02.2010
comment
Марк, я не итерирую, я копирую буферы кусками. Крейг, компьютеры - это магия, верно? :)   -  person Aran Mulholland    schedule 11.02.2010
comment
Компьютеры могут быть очень крутыми, что, я думаю, является грубым приближением к магии для некоторых целей. :-)   -  person Craig McQueen    schedule 11.02.2010
comment
вы заметили волшебный тег? я даже не добавляла...   -  person Aran Mulholland    schedule 11.02.2010
comment
Вы имеете в виду архитектуру процессора и размер буфера? Они могут повлиять на алгоритм. Например, x86 со 128-битными буферами немного отличается от x64 со 128-битными буферами. А ARM с NEON может использовать другой алгоритм, чем x86/x64. Буферы уникальны или вы можете работать на месте? 128-битный буфер немного отличается от 256-битного или 512-битного буфера на x86/x64 из-за AVX. И фиксированный буфер отличается от неизвестного или произвольного размера буфера.   -  person jww    schedule 10.04.2017


Ответы (2)


Это работает для копирования ints в обратном порядке:

void reverse_intcpy(int *restrict dst, const int *restrict src, size_t n)
{
    size_t i;

    for (i=0; i < n; ++i)
        dst[n-1-i] = src[i];

}

Как и memcpy(), области, на которые указывают dst и src, не должны перекрываться.

Если вы хотите изменить на месте:

void reverse_ints(int *data, size_t n)
{
    size_t i;

    for (i=0; i < n/2; ++i) {
        int tmp = data[i];
        data[i] = data[n - 1 - i];
        data[n - 1 - i] = tmp;
    }
}

Обе вышеуказанные функции являются портативными. Возможно, вы сможете ускорить их, используя аппаратно-зависимый код.

(Я не проверял код на правильность.)

person Alok Singhal    schedule 11.02.2010
comment
какова эффективность этого по сравнению с memcpy? - person Aran Mulholland; 11.02.2010
comment
memcpy должно быть O(n), как и эта функция reverse_memcpy. - person dreamlax; 11.02.2010
comment
При моем быстром тестировании с -O3 оптимизацией reverse_memcpy() примерно в 3 раза медленнее, чем memcpy() при копировании 1000000 байт. Для 10 000 итераций с 1 000 000 байт memcpy() заняло 4 секунды, а reverse_memcpy() — 11. Но эти цифры для очень конкретного случая, так что вы можете проверить сами. Конечно, как сказал Dreamlax, оба являются O (n). - person Alok Singhal; 11.02.2010
comment
Это тоже неправильно; если исходные данные выборки представлены целыми числами без знака, это также изменит их на байты. - person Andrew McGregor; 11.02.2010
comment
@Андрей, да. Фиксация. Спасибо! - person Alok Singhal; 11.02.2010
comment
Замедление, вероятно, связано с тем, что ваши операции чтения и записи не выровнены. memcpy, вероятно, работает быстрее, копируя выровненные фрагменты памяти (когда это возможно). - person dreamlax; 11.02.2010
comment
Вышеупомянутое просто сломано. К тому времени, когда петля достигнет половины пути, вторая половина будет перезаписана перевернутой первой половиной. 1,2,3,4 не станут 4,3,2,1, а на самом деле будут 1,2,2,1. Нужно добавить чтение с конца и чтение с начала, поменять местами, а затем записать значения обратно. - person mP.; 11.02.2010
comment
@mP - memcpy будет иметь тот же результат, так как предполагает, что два указателя не перекрываются, и оптимизирован на этом предположении. Стандартная библиотека memmove используется в конкретном случае, когда два указателя могут указывать на перекрывающееся пространство. Если OP хочет поведения, подобного memmove, он должен указать это. Если ОП хочет обратного поведения на месте, он также должен указать это, поскольку этот случай может быть оптимизирован. - person Chris Lutz; 11.02.2010
comment
@mP: я понял, что ОП может захотеть изменить ситуацию на месте. Я редактировал свой пост, когда вы оставили комментарий. Согласен с вашей точкой зрения полностью. В первом выпуске моего ответа было предупреждение о необходимости непересекающихся регионов и использовании ключевого слова restrict в C99... - person Alok Singhal; 11.02.2010
comment
@Alok: я заметил, что вы отредактировали ответ, но похоже, что OP действительно хочет решения, при котором буфер копируется и реверсируется. - person dreamlax; 11.02.2010
comment
@dreamlax: да, я тоже так прочитал вопрос, но на всякий случай отредактировал его. Спасибо за ваши комментарии. - person Alok Singhal; 11.02.2010
comment
@Aran, memcpy и эти обратные функции выполняют разные операции, поэтому сравнение эффективности совершенно бессмысленно. Либо вам нужно его перевернуть, тогда вам нужно написать свою собственную функцию и сравнить ее различные реализации, когда вы обнаружите, что она слишком медленная. Или вам не нужно его переворачивать, тогда просто используйте memcpy или memmove. - person Secure; 11.02.2010
comment
Первая версия выиграла бы от restrictаргументов. - person Alexandre C.; 25.05.2015
comment
@АлександрК. согласованный. Тем более, что это не работает, если аргументы перекрываются. - person Alok Singhal; 25.05.2015
comment
Вы можете упростить код на месте с помощью двух переменных: void reverse_ints(int *data, size_t n) { if (n < 2) return; for (size_t i=0, j=n-1; i < j; ++i, --j) { int tmp = data[i]; data[i] = data[j]; data[j] = tmp; } } - person Jonathan Leffler; 26.05.2015
comment
@JonathanLeffler, конечно. Есть много способов написать этот цикл. - person Alok Singhal; 26.05.2015
comment
Я никогда особо не задумывался об измерении производительности реализации memcpy с помощью временной сложности. Это не правильный инструмент для работы. Почти все мы можем согласиться с тем, что O(n) всегда будет иметь место, если только что-то не пошло не так! Выполнение параллельных тестов с различными наборами данных в равных условиях — это то, что нужно. - person nuzzolilo; 12.06.2016
comment
Я хочу что-то с эффективностью memcpy. Учитывая кэши памяти, SSE и тому подобное, это решение будет медленным. И, как говорит Нуццолило, вопрос здесь не в большом О. - person sudo; 06.03.2017
comment
@Nuzzolilo - Что касается тестов, определенно согласен. Я ищу переносимый шаблон, который компиляторы, такие как Clang, GCC, ICC и MSVC, распознают для создания кода, специфичного для архитектуры, например SSE2 (128-битные буферы), NEON (128-битные буферы), AVX (256-битные буферы) и AVX-512 (512-битные буферы). - person jww; 10.04.2017

Нет, memcpy не сделает этого в обратном порядке. Если вы работаете на C, напишите для этого функцию. Если вы действительно работаете на C++, используйте std::reverse или std::reverse_copy.

person janm    schedule 11.02.2010
comment
Я знаю, что это старо, но не могли бы вы опубликовать пример функции, которая это делает? Это просто, но может кому поможет. - person Austin Mullins; 17.07.2014