比memcpy更快的方式来复制以0结尾的字符串

时间:2017-07-16 10:41:04

标签: c++ string memcpy strcpy strdup

我有一个关于复制以0结尾的字符串的问题:

const char * str = "Hello World !";
size_t getSize = strlen(str);
char * temp = new char[getSize + 1];

...我知道我可以使用这个功能

memcpy(temp, str, getSize);

但我想使用我自己的复制功能,其功能如下

int Count = 0;
while (str[Count] != '\0') {
    temp[Count] = str[Count];
    Count++;
}
这两种方式都是真实而成功的。现在我想以10百万次检查它,并为memcpy做这个动作

const char * str = "Hello World !";
size_t getSize = strlen(str);
for (size_t i = 0; i < 10000000; i++) {
    char * temp = new char[getSize + 1];
    memcpy(temp, str, getSize);
}

这是我自己的方式

    const char * str = "Hello World !";
    size_t getSize = strlen(str);
    for (size_t i = 0; i < 10000000; i++) {
        char * temp = new char[getSize + 1];
        int Count = 0;
        while (str[Count] != '\0') {
            temp[Count] = str[Count];
            Count++;
        }
    }

第一个过程在 420毫秒完成,第二个过程在 650毫秒完成 ......为什么?这两种方式都是一样的!我想使用自己的功能而不是memcpy。有没有办法让自己的方式更快(快速,因为memcpy快或可能更快)? 如何更新自己的方式(同时)使其更快或与memcpy相等?

完整的来源

int main() {

    const char * str = "Hello world !";
    size_t getSize = strlen(str);

    auto start_t = chrono::high_resolution_clock::now();
    for (size_t i = 0; i < 10000000; i++) {
        char * temp = new char[getSize + 1];
        memcpy(temp, str, getSize);
    }
    cout << chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - start_t).count() << " milliseconds\n";


    start_t = chrono::high_resolution_clock::now();
    for (size_t i = 0; i < 10000000; i++) {
        char * temp = new char[getSize + 1];
        int done = 0;
        while (str[done] != '\0') {
            temp[done] = str[done];
            done++;
        }
    }
    cout << chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - start_t).count() << " milliseconds\n";

    return 0;
}

结果:

482毫秒
654毫秒

3 个答案:

答案 0 :(得分:3)

用您自己的库替换库函数通常会导致性能下降。

memcpy表示非常基本的内存操作。因此,它的作者高度优化。与“天真”实现不同,只要有可能,库版本就会一次移动多个字节,并在可用的平台上使用硬件辅助。

此外,编译器本身“知道”memcpy和其他库函数的内部工作方式,并且可以在编译时知道长度的情况下完全优化它们。

注意:您的实现的语义为strcpy,而不是memcpy

答案 1 :(得分:1)

  

......这两种方式都是一样的!

不,他们不是:

  1. memcpy()不会检查每个字符是否包含'\0'
  2. 实施者可能会比您的天真方法做出更多优化
  3. 您的方法不可能比memcpy()更快。

答案 2 :(得分:0)

看到你没有使用指针并将你正在做的事情(strcpy)与memcpy进行比较,清楚地表明你是一个初学者,而且正如其他人已经说过的那样,很难超过一个有经验的程序员,比如编写你的库的人

但我会给你一些提示来优化你的代码。 我快速浏览了一下微软的C标准库实现(被称为C运行时库),他们在汇编中这样做比在C中做得快。所以这是速度的一点。

在大多数具有32位总线的32位架构中,CPU可以在一次请求中从内存中获取32位信息(假设数据已正确对齐),但即使您需要16位或8位,它仍然需要提出1个请求。因此,使用机器的字大小可能会让您加快速度。

最后,我想引导您注意SIMD。如果您的CPU提供它,您可以使用它并获得额外的速度。 MSCRT再次提供了一些SSE2优化选项。

在过去,我不得不编写优于我的库实现的代码,因为我有一个特定需求或特定类型的数据,我可以优化,虽然它可能具有一定的教育价值,除非特别需要,花在重新实现库函数上的时间最好花在实际代码上。