Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the purpose of the casts to signed int in glibc memmove?

Source code

There they do

unsigned long int dstp = (long int) dest;
unsigned long int srcp = (long int) src;

/* This test makes the forward copying code be used whenever possible.
   Reduces the working set.  */
if (dstp - srcp >= len)       /* *Unsigned* compare!  */
  {
    /* Copy from the beginning to the end.  */

I understand why they go through the trouble of casting to longs in the first place: it is to avoid Undefined Behavior by comparing pointers to (probably) different objects. And they obviously have to use unsigned longs to do the actual comparison.

But why do they cast to long int first, then implicitly to unsigned long int?

like image 894
John Smith Avatar asked Mar 08 '16 19:03

John Smith


1 Answers

First, the parameters passed into the function are of type void* and const void*. In order to determine the addresses in a way that is comparable, they are cast to an integer type (long int). This first cast does an integer conversion so that the void* pointers can be compared numerically.

Second, some non-ANSI compilers may implement implicit casts from void* to integer types in a non-uniform manner and may lose some precision. On many platforms, the size of a long is the same as the size of a void* (though this is not true on all platforms), and casting from a void* to a long is an appropriate way to represent an address.

Third, the conversion from long int to unsigned long int serves two purposes: to ensure that large addresses are not mistaken as negative numbers during comparison, and to allow better safety for non-ANSI compilers. The function you are referencing in your code is concerned with memory alignment and overlapping memory regions in dest and src and to determine whether the memory movement will go from beginning to end or end to beginning. Unsigned comparisons are used here to better evaluate that possibility of overlapping memory regions, and how to handle it appropriately.

Some non-ANSI compilers may not properly convert directly from void* to unsigned long int (depending on implementation) and may truncate the pointer. The cast from void* to long int to unsigned long int should preserve the bit representation at each step so that the actual address is not corrupted.

like image 187
callyalater Avatar answered Oct 28 '22 05:10

callyalater