112
votes

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?

2
question reminds me a bit of checking for null pointers on functions like free. Not necessary, but I would put a comment there to show you thought about it.Toad
@Toad: What purpose does that serve, other than to clutter up the code? When reading someone's code, I don't need to know that the original programmer "thought about doing this operation which isn't actually necessary, but because it's unnecessary, I didn't do it". If I see a pointer beeing freed, I know it is allowed to be null, so I don't need to know the thoughts of the original programmer on the subject of "should I check for null". And the same goes for copying 0 bytes with memcpyjalf
@jalf: the fact that it is a question on stackoverflow, makes it something people doubt. So adding a comment may not help you, but might help someone with less knowledgeToad
@Toad Yeah, comments explicitly calling out why a check that looks necessary really isn't can be valuable in principle. The other side of the coin is that this particular example is a common case involving a standard library function that each programmer only needs to learn the answer to once; then they can recognise in any program they read that these checks aren't needed. For that reason, I'd omit the comments. A codebase with multiple calls like this is either gonna need to copy and paste the comments to each one, or arbitrarily use them on only some calls, both of which are ugly.Mark Amery

2 Answers

151
votes

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 (or yes; you can pass zero).

5
votes

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.