6

Is this ok?

char buf[] = { 0, 1, 2 };
memcpy(buf, buf + 1, 2);

Does having a bigger datatype make any difference? I know I could use memmove(), but I'm just curious.

Stockhausen
  • 287
  • 5
  • 13
  • -1: what hapenned when you tried? – pmg Mar 15 '11 at 12:03
  • 3
    +1, because I disagree with pmg's -1. "What happened when you looked it up in the standard?", maybe, but there's a real risk in experimenting with this kind of thing, that you might try it and it "works", with result `{1,2,2}` in the buffer. Then what use is the advice to try it? Will it still work next week, or when you turn on optimization, or on your customers' computers? – Steve Jessop Mar 15 '11 at 12:37
  • @Steve Jessop: I agree. The OP's example will (probably) work, depending on the particular target platform implementation of `memcpy`, but that doesn't make it a good idea! – GrahamS Mar 15 '11 at 12:42
  • Thing is: he says *"I know I could use memmove()"* and he still asks if `memcpy()` is ok. How does he know he could use memmove and **NOT KNOW** not to use memcpy with overlapping objects? – pmg Mar 15 '11 at 18:56
  • @pmg: I guess I was somewhat unclear. I somehow failed to found a definite answer for it being undefined behavior, but obviously didn't leave such thing in code. I tried it out of curiosity, and it worked for my compiler in this particular case. – Stockhausen Apr 11 '11 at 09:48
  • The GNU C Library has switched the implementation of memcpy around a few times. Sometimes it's even different for i686 vs i386 vs x86_64. – Zan Lynx Apr 11 '12 at 22:19

4 Answers4

13

The effects of memcpy are not defined when the input and output overlap. You should use memmove.

Gareth McCaughan
  • 19,888
  • 1
  • 41
  • 62
5

Not okay. You must use memmove when the source and destination overlap.

It might work with memcpy, depending on your compiler's implementation, but that is not something you should rely on!


A typical naive implementation might be a byte-by-byte copy (uint8) like this:

typedef unsigned char uint8;

void * memcpy ( void * destination, const void * source, size_t num )
{
    const uint8* pSrc = (const uint8*)source;
    const uint8* const pSrcEnd = pSrc + num;
    uint8* pDst = (uint8*)destination;

    while (pSrc != pSrcEnd)
        *(pDst++) = *(pSrc++);

    return destination;
}

which would work okay with your memcpy(buf, buf + 1, 2), but less well with memcpy(buf + 1, buf, 2)

GrahamS
  • 9,980
  • 9
  • 49
  • 63
4

The behavior is undefined if the memory regions overlap, so this is not ok.

Asha
  • 11,002
  • 6
  • 44
  • 66
1

It is undefined behaviour, but I have used it like so,

char buf[] = {0, 1, 2, 3);
memcpy(buf, buf+2, 2);

where the end point of the destination is less than the start point of the source. You should still use memmove to be sure...

DavidMFrey
  • 1,658
  • 1
  • 14
  • 14
  • The GNU C Library has switched the implementation of memcpy around a few times. Sometimes it's even different for i686 vs i386 vs x86_64. – Zan Lynx Apr 11 '12 at 22:19