131

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?

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • 6
    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 Sep 20 '10 at 13:19
  • 12
    @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 `memcpy` – jalf Sep 20 '10 at 14:59
  • 10
    @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 knowledge – Toad Sep 20 '10 at 15:45
  • 2
    @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 Jan 11 '19 at 11:47

2 Answers2

173

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).

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • 3
    Would a pointer be considered "valid" for purposes of such a function if it pointed to the location following the last element of an array? Such a pointer could not be legitimately deferenced, but one could safely do some other pointer-ish things like subtract one from it. – supercat Nov 20 '11 at 22:19
  • 1
    @supercat: yes, a pointer that points one past the end of an array is valid for pointer arithmetic with other pointers within (or one past the end of) that array, but is not dereferencable. – Mike Seymour Nov 20 '11 at 22:25
  • @MikeSeymour: Shouldn't the citation imply an opposite answer: the check is necessary and you can't pass zero with null pointers? – neverhoodboy Mar 20 '14 at 16:17
  • 7
    @neverhoodboy: No, the quote clearly says "`n` can have the value zero". You're correct that you can't pass null pointers, but that's not what the question is asking about. – Mike Seymour Mar 20 '14 at 16:18
  • 3
    @MikeSeymour: My fault. Really sorry. The question is about the size not the pointer. – neverhoodboy Mar 20 '14 at 16:22
  • "You're correct that you can't pass null pointers, but that's not what the question is asking about." The OP didn't specify what `source` is. Very often in these cases where the length is 0, the address being copied is NULL. In those cases, the standard requires a check--but you can usually get away without it, since `memmove` doesn't check and implementations where NULL is a trap value are nonexistent AFAIK. – Jim Balter Jul 23 '20 at 20:05
6

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
  • 123,740
  • 17
  • 206
  • 299
  • 1
    I would think this function is probably made in assembly where you can optimize memory tranfers much better than in c – Toad Sep 20 '10 at 13:43
  • *"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 Sep 20 '10 at 13:52
  • 11
    -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.. GitHub STOP HELPING ICE Sep 20 '10 at 14:03
  • 4
    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 Sep 20 '10 at 14:05