之前写过一篇关于 memcpy函数面试的文章
几个简单的笔试题
里面的代码使用的是char指针来实现,今天我们来看看Linux下面的memcpy
函数,它的实现上还是有一些巧妙的。
void * memcpy(void * dest, const void *src, size_t n)
{if (!(((unsigned long) dest ^ (unsigned long) src) & 7)) {__memcpy_aligned_up ((unsigned long) dest, (unsigned long) src,n);return dest;}__memcpy_unaligned_up ((unsigned long) dest, (unsigned long) src, n);return dest;
}
首先,函数会对参数判断地址是不是对齐的,如果是对齐的话,会调用对齐的内存拷贝函数,如果是不对齐的话,会调用不对其的函数。
正常情况下,地址都会是按4字节对齐的
看看__memcpy_aligned_up 函数
/** Hmm.. Strange. The __asm__ here is there to make gcc use an integer register* for the load-store. I don't know why, but it would seem that using a floating* point register for the move seems to slow things down (very small difference,* though).** Note the ordering to try to avoid load (and address generation) latencies.*/
static inline void __memcpy_aligned_up (unsigned long d, unsigned long s,long n)
{ALIGN_DEST_TO8_UP(d,s,n);n -= 8;while (n >= 0) {unsigned long tmp;__asm__("ldq %0,%1":"=r" (tmp):"m" (*(unsigned long *) s));n -= 8;s += 8;*(unsigned long *) d = tmp;d += 8;}n += 8;DO_REST_ALIGNED_UP(d,s,n);
}
我们直接看代码操作就很清楚了,是按照8个字节来做的偏移
我写了个测试程序,测试程序和内核代码有一些小出入,主要是我用的是devc++来写代码,unsigned long并不是8字节。
测试代码如下
#include <stdio.h>
#include <string.h>void * cris_memcpy(void *out, const void *in, unsigned int length) {if (!(((unsigned long) out ^ (unsigned long) in) & 7)) {printf("aligned\n");} if (out == NULL || in == NULL) {return NULL;}while (length) {*(char*)out++ = *(char*)in++;length = length - 1;}return out;
}typedef unsigned long long usize8_t;static inline void __memcpy_aligned_up (usize8_t d, usize8_t s,long n) {if (!(((usize8_t) d ^ (usize8_t) s) & 7)) {printf("aligned\n");} //n -= 8;printf("%d %d\n",n,sizeof(usize8_t));while (n >= 0) {usize8_t tmp;tmp = *(usize8_t *) s;n -= 8;s += 8;*(usize8_t *) d = tmp;d += 8;}n += 8;
}int main() {char a[20] = "happy new year";char b[20];char c[20];cris_memcpy(&b, &a, strlen(a));__memcpy_aligned_up(&c, &a, strlen(a));printf("a=%s\n",a);printf("b=%s\n",b);printf("c=%s\n",c);return 0;
}
代码输出
最后,如果觉得不错,大家顺手点个赞,转发就是对我最大的鼓励和支持!
长按识别二维码关注公众号