memcpy

James C Burley burley at world.std.com
Sat Sep 22 01:12:21 AEST 1990


In article <13914 at smoke.BRL.MIL> gwyn at smoke.BRL.MIL (Doug Gwyn) writes:

   ...  Some memcpy() implementations
   have attempted to "do the right thing" (meaning: follow the sequential
   pick-the-entire-block-up-into-a-temporary-register, then-put-the-
   temporary-register-contents-back-down-at-the-new-location model) for
   cases of overlaps, while others have not.

First off, it strikes me (THUNK!  :-) that my expectation of what memmove
would do is exactly the opposite of what is desired.  If one wants to use
a memory move to spew a given set of values (in the case discussed here,
just one) across memory, and indeed the more-than-one case is not covered
to my knowledge my memset or any other ANSI function, it seems that one does
not want to use a memory move that is "smart enough" to do an overlapping
move the "right" way.  If I have

char array[5] = [ 1, 2, 3, 4, 5 ];

and I memmove 4 bytes from array[0] to array[1], personally I would expect
the more natural result to be:

[ 1, 1, 2, 3, 4 ]

But the original posting seems to be asking for

[ 1, 1, 1, 1, 1 ]

Similarly, taking the original array and memmoving (sigh) 4 bytes from
array[1] to array[0], I'd think one should get:

[ 2, 3, 4, 5, 5 ];

But again someone else might want:

[ 5, 5, 5, 5, 5 ];

So I read the statement "memmove handles overlapping copies correctly" to
mean what is stated above in the reference posting I've included: the copy
happens AS IF the source array were copied into a temporary, then copied
into the destination.  What the original posting appears to ask for is a
copy that does the "wrong" thing.

Second, I don't think it is necessary for memmove to actually copy into a
temporary.  I think one can do an implementation similar to the following
(I've probably made a couple of mistakes, but you get the idea):

void *memmove(void *source,void *dest,size_t n)
{
void *save;

/* Let's not bother with (char *) casts, ok? (-:  Actually the copies can
   be done using casts to int * or long * if the proper modulo checking is
   done, for efficiency. */

if ((source == dest) || (n == 0))
    return source;  /* Nothing to do. */

save = source;

if ((source > dest) || (source + n <= dest))
    {  /* Normal case: source follows destination, or no overlap at all. */
    for (; n != 0; n--)
      *dest++ = *source++;
    return save;
    }

/* The source array precedes and overlaps with the destination array, so
   copy the array backwards. */

source += n;
dest += n;

for (; n != 0; n--)
  *--dest = *--source;

return save;
}

This should get the idea across, but probably contains silly mistakes besides
the omission of casts!

James Craig Burley, Software Craftsperson    burley at world.std.com



More information about the Comp.std.c mailing list