memmove函数的实现

memcpymemmove

在C语言中,对于字符串之间的拷贝经常使用的函数有strcpy, strncpy以及memcpy, memmove这几个,其中str系列只可用于字符串间的拷贝,而mem系列为按字节内存拷贝,可用于任何类型数据间的拷贝。为什么有了memcpy还需要有memmove呢?这是Mac平台下的memmove函数,与其它平台不同,不好直接看到源码:

#if __has_builtin(__builtin___memmove_chk) || defined(__GNUC__)
#undef memmove
/* void *memmove(void *dst, const void *src, size_t len) */
#define memmove(dest, ...) \
		__builtin___memmove_chk (dest, __VA_ARGS__, __darwin_obsz0 (dest))
#endif

考虑这种情况,如果dst和src内存地址有重叠,且dst位于src之后,如果从前往后拷贝,那么src中和dst重叠的部分就会先被覆盖,造成拷贝错误,因此需要考虑拷贝顺序的问题:

  • 如果dst在src之后,从后往前拷贝
  • 如果dst在src之前,从前往后拷贝

这样便可以避免发生拷贝错误

memmove的实现

这是一个简易的实现,并没有处理一些细节,如果dst和src地址相同,也可以直接返回的,但是应该需要处理长度问题,Mac平台下不好看源码,也不知道具体源码是怎么实现的。。。

void *memmove(void *dst, const void *src, size_t len) {
  if (len == 0) {
    return NULL;
  }
  if (dst == NULL || src == NULL) {
    return NULL;
  }

  char *_dst = NULL;
  char *_src = NULL;
  if (dst < src) {
    _dst = (char *)dst;
    _src = (char *)src;
    while (len--) {
      *_dst++ = *_src++;
    }
  } else {
    _dst = (char *)dst + len;
    _src = (char *)src + len;
    while (len--) {
      *_dst-- = *_src--;
    }
  }
  return dst;
}

测试

int main() {
  char s1[12] = "hello world";
  char s2[12];
  memmove(s2, s1, 10);
  printf("s2: %s\n", s2);

  return 0;
}
duyong@Mac: Study $ clang memmove.c 
duyong@Mac: Study $ ./a.out 
s2: hello worl
duyong@Mac: Study $ 

版权声明:本文为weixin_42482896原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。