实现自己的memcpy(大小以字节为单位?)

时间:2012-08-09 03:27:18

标签: c++ c

我最近有一个面试问题,我必须实施memcpy。我根据自己的经验使用了memcpy,所以这似乎不是一个棘手的问题。

所以,我开始实现一个循环,一次从指针到指针复制一个地址,如下所示:

void memcpy(void* dest, void* src, int size){
    for(int index = 0; index < size; index++){
        dest[index] = src[index];
    }
}

然而,采访者打断说memcpy的man页面说“将src中的n个字节复制到dest”(后面我确认了)然后想让我用size / 4进行迭代,然后用另一个进行迭代索引循环&lt;大小%4(我想假设它是一个32位系统?)

嗯,这看起来很奇怪,因为我多年来一直使用memcpy没有问题而不必给它一个* 4修饰符)。当我回到家时,我启动了gdb并复制了一个小字符串“hello”,并小心地用strlen()和常量输入大小以查看它的起始和停止位置。

    char* src = "hello";
    char* dest = calloc(16, sizeof(char));
    int len = strlen(src);
    memcpy(dest, src, len); // both my version and official version

现在我仔细检查了src和dest与gdb,它们都包含“hello \ 0”。

所以我的问题是:对于使用数字4(或“字节大小”),我不理解什么?为什么文档说“n字节”时,那不是真正的行为?我在这里看不清楚什么?

7 个答案:

答案 0 :(得分:14)

正如其他人所说,一次复制4个字节比一次复制1个字节要快。面试官希望你做这样的事情:

void memcpy(void* dest, void* src, int size)
{
    uint8_t *pdest = (uint8_t*) dest;
    uint8_t *psrc = (uint8_t*) src;

    int loops = (size / sizeof(uint32_t));
    for(int index = 0; index < loops; ++index)
    {
        *((uint32_t*)pdest) = *((uint32_t*)psrc);
        pdest += sizeof(uint32_t);
        psrc += sizeof(uint32_t);
    }

    loops = (size % sizeof(uint32_t));
    for (int index = 0; index < loops; ++index)
    {
        *pdest = *psrc;
        ++pdest;
        ++psrc;
    }
}

答案 1 :(得分:12)

他们要求你优化你的实现,让它在循环内一次复制一个32位字,一次复制一个字节。这需要仔细检查以处理边界情况,例如size不是4的倍数,或destsrc未在4字节边界上对齐。

答案 2 :(得分:1)

你的memcpy的逻辑是正确的,你的面试官没有要求你改变它或添加限制。一次复制4个字节更快,但如果你的大小不是4的倍数就成了一个问题。因此你的访问者告诉你使用两个循环:第一个一次复制4个字节,第二个循环一个字节时间(最多迭代3次)。

因此,大部分副本都是使用快速的4字节副本完成的,但是你并不限制大小为4的倍数,因为第二个“清理”循环将复制任何不是4的倍数的东西。 / p>

第一个循环:复制uint32_t并按4增加 第二个循环:复制uint8_t并递增1

答案 3 :(得分:1)

面试官正在测试您对计算机体系结构的了解,并希望您优化算法。内存对单词而不是字节进行操作。在32位系统中,字通常为4个字节,读取/写入1个字节所需的时间与读取/写入1个字所需的时间相同。第二个循环是处理你想要复制的字节数不能完全被4个字节整除的情况。

你真正想要的是3个循环。在dest之后和dest +之前的字节的2个循环,当它们不是字对齐时。然后是中间所有单词的另一个循环。

通过利用特定于体系结构的指令,您实际上可以进行更多优化。如果您有兴趣,请查看此文章:http://www.eetimes.com/design/embedded/4024961/Optimizing-Memcpy-improves-speed

答案 4 :(得分:1)

面试官要求您出于某种原因进行过早优化。这通常是一个坏主意。

32位机器确实会比复制4x1字节更快地复制一个32位卡盘。但是优化还有更多。

32位计算机很可能将您的数据放入缓存中,然后突然快速的内存访问可能比CPU指令更具相关性。缓存存储器可能具有各种对齐要求。他们可能更喜欢普通循环,或者他们可能更喜欢32位对齐的块。我不是这方面的专家,因此我避免过早优化并将其留给编译器,编译器希望知道更多关于缓存的信息。

然后有CPU分支预测和指令管道。这个特定的代码是相当确定的,所以这可能不是问题。但根据经验:简单代码比复杂代码产生更有效的分支预测。

此外,存在划分,这在许多CPU架构上都很慢。根据要复制的数据量,分区可能会导致memcpy慢得多。

总结一下:手动优化非常复杂,需要深入了解CPU和硬件。您不能也不应该“优化32位CPU”,您需要了解具体细节。在大多数情况下,编译器将比您更有效地优化代码。特别是库memcpy()通常用内联汇编程序编写,针对特定目标进行了优化。

答案 5 :(得分:0)

他们希望你加快速度。 32位处理器可以比复制8位更快地复制32位。因此,如果有人想要复制4个字节而不是一次只复制一个字节,那么您可以一次完成所有操作。

答案 6 :(得分:0)

检查出来..

void myMemCpy(void *dest, void *src, size_t n)
{
   // Typecast src and dest addresses to (char *)
   char *csrc = (char *)src;
   char *cdest = (char *)dest;

   // Copy contents of src[] to dest[]
   for (int i=0; i<n; i++)
       cdest[i] = csrc[i];
}

For more info