Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!uunet!world!burley From: burley@world.std.com (James C Burley) Newsgroups: comp.std.c Subject: Re: memcpy Message-ID: Date: 21 Sep 90 15:12:21 GMT References: <1990Sep19.021418.11574@maths.tcd.ie> <13914@smoke.BRL.MIL> Sender: burley@world.std.com (James C Burley) Organization: The World Lines: 82 In-Reply-To: gwyn@smoke.BRL.MIL's message of 20 Sep 90 21:26:59 GMT In article <13914@smoke.BRL.MIL> gwyn@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@world.std.com