It's clear that on the vast majority of platforms, an implementation which would process memcpy(anything, anything, 0) as a no-op, regardless of the validity of the source and destination pointers, would be in every way, in essentially every non-contrived scenario, as good or better than one that does anything else.
The way the Standard is written, however, could be interpreted as specifying that compilers are allowed to treat as UB any situation where the destination address is not associated with writable storage.
If one is using an implementation that seeks to process corner cases applying the philosophy documented in the Rationale document published by the authors of the Standard, without regard for whether the Standard unambiguously mandates such behavior, all memcpy
and memmove
operations where the size is zero will be reliably processed as no-ops. If the size will often be zero, there may be performance advantages to skipping a memcpy
or memmove
call in the zero-size case, but such a check would never be required for correctness.
If, however, one wishes to ensure reliable compatibility with compiler configurations that aggressively assumes that code will never receive inputs that trigger corner cases that aren't 100% unambiguously mandated by the Standard, and is designed to generate nonsensical code if such inputs are received, then it will be necessary to add a size==0 check in any case where a zero size might be accompanied by anything other than a pointer to writable storage, recognizing that such a check may negatively affect performance in situations where the size is very seldom zero.