2

I looked at http://www.opensource.apple.com/source/xnu/xnu-2050.24.15/libsyscall/wrappers/memcpy.c

and didn't understand the following :

1-

inside

void * memcpy(void *dst0, const void *src0, size_t length) {
    char *dst = dst0;
    const char *src = src0;

line:

if ((unsigned long)dst < (unsigned long)src) {

How can we cast dst to an unsigned long ? it's a pointer !

2- Why do they sometimes prefer forward copying and sometimes backwards??

9
  • 1
    Probably because the creator of the function knows that on the XNU platform, the type unsigned long is the same size as a pointer? There probably are some static assertions elsewhere that makes sure this is the case. Commented Nov 15, 2013 at 14:25
  • To have the quality of this question enhanced it would be nice to have the declarations of dst and src in place. This way the question would be clear without having to follow the link provided (which however could change over time). Commented Nov 15, 2013 at 14:30
  • @alk Good idea. I added it to the question. Commented Nov 15, 2013 at 14:59
  • pointer is an address, address can be represented as unsigned long Commented Nov 15, 2013 at 15:01
  • 1
    @alk - you will get the compiler complaining if you compare "incompatible pointers". The cleanest way to code this, in my mind, would be if((void*)dst < (void*)src). No need to know how big the pointers are, no compiler complaints (any pointer can be cast to void *). Commented Nov 15, 2013 at 15:37

2 Answers 2

4

You are right, this implementation is non-portable, because it is assuming that a pointer is going to fit in unsigned long. This is not guaranteed by the standard.

A proper type for this implementation would have been uintptr_t, which is guaranteed to fit a pointer.

Sign up to request clarification or add additional context in comments.

2 Comments

Note that uintptr_t is found in stdint.h and requires a somewhat modern C compiler (C99 or later).
Strangely, that same function later does cast the pointers to uintptr_t.
1

When comparing a void* and char* pointer, the compiler will give a warning (gcc -Wall):

warning: comparison of distinct pointer types lacks a cast

I imagine that the developer decided to "make the warning go away" - but the correct way to do this is with a void* cast (which is portable):

if((void*) dst < (void*) src) {

As for the second point - as was pointed out, you have to take care of overlapping memory locations. Imagine the following 8 characters in successive memory locations:

 abcdefgh

Now we want to copy this "3 to the right". Starting with a, we would get (with left-to-right copy):

abcdefgh
abcaefgh
   ^
abcabfgh
   ^^
abcabcgh
   ^^^

etc until you end up with

abcabcabcab
   ^^^^^^^^

When we wanted to get

abcabcdefgh

Starting from the other end, we don't overwrite things we still have to copy. When the destination is to the left of the source, you have to do it in the opposite direction. And when there is no overlap between source and destination, it doesn't matter what you do.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.