views:

216

answers:

4

Do I need to treat cases when I actully have nothing to move/copy with memmove()/memcpy() as edge cases

int numberOfBytes = ...
if( numberOfBytes != 0 ) {
    memmove( dest, source, numberOfBytes );
}

or should I just call the function without checking

int numberOfBytes = ...
memmove( dest, source, numberOfBytes );

Is the check in the former snippet necessary?

+1  A: 

No, the check is not necessary. Relying on zero being handled properly is fine and very reasonable, in my opinion. It might be worth commenting.

unwind
Not necessarily. A very common usage would be insertion and deletion from arrays which might not be `char` arrays. Any array usage might have zero-length move as a natural case and it's nice not to have to special-case that.
R..
+3  A: 

The documentation of memmove and memcpy says this:

The function does not check for any terminating null character in sourceit always copies exactly num bytes.

The opengroup documentation says basically the same thing.

So, given that it copies "exactly num bytes", it will copy zero bytes when num = 0, and thus it shouldn't be necessary to treat this as a special case.

You
Who upvoted this anwser? It has to do nothing with the question.
qrdl
If it always copies exactly *num* bytes, it won't have any problem to copy exactly 0 bytes. :)
Matteo Italia
@qrdl: It does, it answers the question "do I need to treat `num = 0` as a special case?".
You
@You OP asked about edge condition, so giving the common-case response isn't appropriate. `num = 0` bit appeared after the edit.
qrdl
@qrdl; agreed, the initial wording might have been a bit too general. Hence the edit.
You
+12  A: 

From the C99 standard (7.21.1/2):

Where an argument declared as size_t n specifies the length of the array for a function, n can have the value zero on a call to that function. Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values, as described in 7.1.4. On such a call, a function that locates a character finds no occurrence, a function that compares two character sequences returns zero, and a function that copies characters copies zero characters.

So the answer is no; the check is not necessary.

Mike Seymour
+1 for standard citation
R..
+1  A: 

As said by @You, the standard specifies that the memcpy and memmove should handle this case without problem; since they are usually implemented somehow like

void *memcpy(void *_dst, const void *_src, size_t len)
{
    unsigned char *dst = _dst;
    const unsigned char *src = _src;
    while(len-- > 0)
        *dst++ = *src++;
    return _dst;
}

you should not even have any performance penality other than the function call; if the compiler supports intrinsics/inlining for such functions, the additional check may even make the code a micro-little-bit slower, since the check is already done at the while.

Matteo Italia
I would think this function is probably made in assembly where you can optimize memory tranfers much better than in c
Toad
*"somehow like"* :) Actually almost all the implementations I've seen are in assembly, and try to copy most of the bits using the native word size (e.g. uint32_t on x86), but that doesn't change the substance of the answer: it's a *while* loop that doesn't need great calculations before starting, so the check is already done.
Matteo Italia
-1, the typical implementation is irrelevant to whether it's valid C to call these functions (which may not even be implemented as C functions) with a zero argument.
R..
The fact that it's valid C has already been covered by the other answers, as I said at the very beginning of my answer: "As said by @You, _the standard_ specifies that the memcpy and memmove should handle this case without problem". I just added my opinion on the fact that you should not even have fear of calling memcpy with len=0 for performance reasons, since in that case it's a call with an almost zero cost.
Matteo Italia