Code snippets:portable memmove

From C

Jump to: navigation, search

Many memmove attempts attempt to compare s1 and s2 with a relational operator such as < or >. Unfortunately, however, this is not really portable. In C99, for example, 6.5.8p5 implies that if the relational operators are used with objects that are not sub-objects (including sub-sub-objects, and so on) of the same ultimate parent object, then the behaviour is undefined.

 /* Shao Miller, 2012 */
 
 #include <stdio.h>
 #include <stdlib.h>
 
 void * pmemcpy(void * s1, const void * s2, size_t n);
 void * pmemmove(void * s1, const void * s2, size_t n);
 
 int main(void) {
     char test1[] = "0123456789";
     char test2[] = "ABCDEFGHIJ";
     char * t1;
     char * t2;
 
     t1 = pmemmove(test1, test1 + 5, 5);
     t2 = pmemmove(test2 + 5, test2, 5);
     (void) t2;
 
     printf("%s\n%s\n", t1, test2);
 
    return EXIT_SUCCESS;
  }
 
 void * pmemcpy(void * s1, const void * s2, size_t n) {
     unsigned char * dest;
     const unsigned char * src;
 
     if (!s1 || !s2 || !n)
       return s1;
 
     dest = s1;
     src = s2;
 
     while (n--)
       *dest++ = *src++;
 
     return s1;
   }
 
 /* Portability wins over performance, here */
 void * pmemmove(void * s1, const void * s2, size_t n) {
     unsigned char * dest;
     const unsigned char * src;
     const unsigned char * src_end;
 
     if (!s1 || !s2 || !n || s1 == s2)
       return s1;
 
     dest = s1;
     src = s2;
 
     /* The only interesting case is where src < dest with overlap */
     for (src_end = src + n; src < src_end; ++src) {
         if (src == dest)
           break;
       }
 
     /* Is src > dest or non-overlapping? */
     if (src == src_end)
       return pmemcpy(s1, s2, n);
 
     /* Otherwise, src < dest with overlap */
     dest += n;
     src = src_end;
 
     while (n--)
       *dest-- = *src--;
 
     return s1;
   }
Personal tools