views:

631

answers:

2

I am working with audio data. I'd like to play the sample file in reverse. The data is stored as unsigned ints and packed nice and tight. Is there a way to call memcpy that will copy in reverse order. i.e. if i had 1,2,3,4 stored as ints in an array could i memcpy and magically reverse them so i get 4,3,2,1

+3  A: 

No, memcpy won't do that backwards. If you're working in C, write a function to do it. If you're really working in C++ use std::reverse or std::reverse_copy.

janm
+3  A: 

This works for copying ints in reverse:

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

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

}

Just like memcpy(), the regions pointed-to by dst and src must not overlap.

If you want to reverse in-place:

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;
    }
}

Both the functions above are portable. You might be able to make them faster by using hardware-specific code.

(I haven't tested the code for correctness.)

Alok
whats the effeciency of this in comparison with memcpy?
Aran Mulholland
`memcpy` should be O(n) and so should this `reverse_memcpy` function.
dreamlax
With my quick testing, with `-O3` optimization, `reverse_memcpy()` is about 3 times slower than `memcpy()` for copying 1000000 bytes. For 10000 iterations with 1000000 bytes, `memcpy()` took 4 seconds, and `reverse_memcpy()` took 11. But these numbers are for a very specific case, so you may want to test things for yourself. Of course, as dreamlax said, both are O(n).
Alok
It's not correct either; if the original sample data is in unsigned ints, this will also byte-reverse it.
Andrew McGregor
@Andrew, yes. Fixing. Thanks!
Alok
The slowdown is probably because your reads and writes aren't aligned. `memcpy` probably works faster by copying aligned chunks of memory (when it can).
dreamlax
The above is plain broken. By the time the loop reaches half way it will have overwritten the second half with the "reversed" first half.1,2,3,4 wont become 4,3,2,1 but will actually be 1,2,2,1. One needs to add a read from the end and a read from the beginning , swap and then write the values back.
mP
@mP only if `dst==src`.
Craig McQueen
@mP - `memcpy` will have the same result, as it assumes the two pointers do not overlap and is optimized on that assumption. The standard library `memmove` is used in the specific case where the two pointers may point to overlapping space. If the OP wants `memmove`-like behavior, he should specify it. If the OP wants reverse-in-place behavior, he should specify that as well, as that case can possibly be optimized.
Chris Lutz
@mP: I realized that the OP might want to reverse in-place. I was editing my post when you made the comment. Agree with the your point completely. The "first edition" of my answer had a warning about the need for non-overlapping regions and the use of `restrict` keyword in C99...
Alok
@Alok: I noticed you edited the answer, but it appears as if the OP actually does want a solution where the buffer is both copied *and* reversed.
dreamlax
@dreamlax: yes, that is how I read the question too, but I edited it anyway just in case. Thanks for your comments.
Alok
@Aran, memcpy and these reverse functions perform different operations, thus a comparison of efficiencies is quite meaningless. Either you need it to be reversed, then you have to write your own function and can compare different implementations of it when you find it to be too slow. Or you don't need it reversed, then simply use memcpy or memmove.
Secure