0

I am a complete novice in C, so this might be a stupid question.

In the implementations of memmove I find online, the code does the following:

void *memmove(void *dest, const void *src, size_t len) {
  char *d = dest;
  const char *s = src;
  if(d < s) {
    while(len--)
      *d++ = *s++;
  } else {
    ...
  }
  return dest;
}

What does comparing the strings d and s with the < operator do? From my understanding, when you compare two strings in C you tend to want to use something like strcmp(). Does it just compare the first character of d and s, or does it look at the whole string?

tomAwa
  • 46
  • 8

2 Answers2

5

If you compare pointers, you are actually comparing the pointer addresses. if (d < s) is literally deciding if d points to a lower memory address than s.

It is doing this in order to handle overlapping memory ranges. If d were to point higher in memory than s, copying in the low to high could end up clobbering bytes that hadn't been copied from yet. So in that case, the function copies bytes from high to low instead.

Edit (thanks to Eric Postpischill):

It should be noted this code is okay for library code that can rely on specific compiler properties, but it is not okay for strictly conforming C code, as the C standard does not define the behavior of applying < to pointers to things that are not part of the same array (or one beyond it, and counting a single object as an array of one element).

Fred Larson
  • 60,987
  • 18
  • 112
  • 174
  • 1
    If we change `d < s` to `len <= (size_t) (d-s)`, this `memmove` will work even if one of the buffers wraps around the end of the address space. – Eric Postpischil Nov 19 '20 at 21:29
4

Unlike memcpy the function memmove allows overlapping memory areas, i.e. a part of the destination area is allowed to be a part of the source area. Therefore the implementation must make sure that the source area isn't overwritten by the destination area data before the source area data has been read.

The code

if(d < s) {

checks that the destination area is placed in memory before the source area. If so it's safe to copy from source to destination char-by-char starting from the lowest address and going towards higher addresses.

In other words, when the comparision d < s is true, it's safe to "move the memory" using a simple copy-loop like:

    while(len--)
       *d++ = *s++;

So to answer your specific question, i.e.

Does it just compare the first character of d and s, or does it look at the whole string?

Neither. It's not a string compare in any way. It's not a character compare in any way.

The code is comparing pointers to the two areas (i.e. destination and source area) to figure out how the memory move can be done.

Edit:

As mentioned in a number of comments (Andrew Henle, M.M.) the C standard doesn't allow comparing pointers that point to different objects (which the shown memmove code may do). However, when looking at a specific implementation of memove, the implementation is for a specific system. So despite the code not being strictly standard compliant, the designers know that it will actually work on the system, it was designed for.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • 1
    *The code do this by comparing pointer to the two areas.* And doing **that** is something an implementation can do safely - it's able to make assumptions that can not be made in strictly-conforming C code. For example, in strictly-conforming C code, a pointer comparison of pointers referring to two different objects is meaningless. – Andrew Henle Nov 19 '20 at 20:50
  • 1
    Note that `if (d < s)` would be undefined behaviour in user-space code (relational comparison can only be used on pointers to the same object), but implementation headers don't have to obey the standard since they can be tailored to behaviour of the specific compiler they are designed to work with . – M.M Nov 19 '20 at 20:51
  • @AndrewHenle When looking into a specific implementation of the standard function, you always look at something tailored to your specific system – Support Ukraine Nov 19 '20 at 20:54
  • 2
    @4386427 You know that, I know that, a lot of others who frequent this site know that. But the random internet reader who was redirected here from Retro Computing because his old, weird computer with a clear round monitor started summoning flying monkeys when he invoked UB by comparing two unrelated pointers doesn't know that. [Like this](https://www.youtube.com/watch?v=xBCXCwW5pRw). :-) – Andrew Henle Nov 19 '20 at 21:02
  • 1
    @AndrewHenle Well, ok - From the comments I understand that it's considered important to include the compliance aspect in the answer. I have edited the answer. Thanks for your feedback. – Support Ukraine Nov 20 '20 at 06:28
  • Thanks for pointing out the pointer comparison issue. For a long time I was wondering how this trick can be used safely and the answer is that indeed in order to use it one has to assume some things about the implementation. BTW it's surprising that in his book on the standard library, P. J. Plauger uses this trick but says nothing about this issue. – meniadin Jun 07 '23 at 21:16