为什么strcmp比我的功能快得多?

时间:2013-12-22 22:55:12

标签: c++ performance time strcmp

我编写了一个函数Str::Compare,它基本上是以另一种方式重写的strcmp。 在比较这两个函数时,在循环中重复500'000'000次,strcmp执行速度太快, x750 快一倍。

此代码是在C库中编译的,-Os参数为active:

int Str::Compare(char* String_1, char* String_2)
{
    char TempChar_1, TempChar_2;

   do
   {
        TempChar_1 = *String_1++;
        TempChar_2 = *String_2++;
   } while(TempChar_1 && TempChar_1 == TempChar_2);

   return TempChar_1 - TempChar_2;
}

该功能的执行时间为3.058s,而strcmp的执行时间仅为0.004s

为什么会这样?

这也是我实现基准测试循环的方式:

int main()
{
     char Xx[] = {"huehuehuehuehuehuehuehuehuehuehuehuehuehue"},
          Yy[] = {"huehuehuehuehuehuehuehuehuehuehuehuehuehue"};
     for(int i = 0; i < 500000000; ++i)
         Str::Compare(Xx, Yy);
}

修改: 在测试我写的一些代码和优化时,我们提高了Str::Compare速度。 如果在strcmp x750 之前,现在只有 x250 。这是新代码:

int Str::Compare(char* String_1, char* String_2)
{
     char TempChar_1, TempChar_2, TempChar_3;

     while(TempChar_1 && !TempChar_3)
     {
          TempChar_1 = *String_1++;
          TempChar_2 = *String_2++;
          TempChar_3 = TempChar_1 ^ TempChar_2;
     }

     return TempChar_1 - TempChar_2;
}

新执行时间为0.994s

3 个答案:

答案 0 :(得分:24)

我很好奇并建立了一个测试程序:

#include <string.h>

compare(char* String_1, char* String_2)
{
    char TempChar_1,
         TempChar_2;

   do
   {
        TempChar_1 = *String_1++;
        TempChar_2 = *String_2++;
   } while(TempChar_1 && TempChar_1 == TempChar_2);

   return TempChar_1 - TempChar_2;
}


int main(){
    int i=strcmp("foo","bar");
    int j=compare("foo","bar");

    return i;
}

我使用gcc 4.7.3将其编译为汇编程序gcc -S -Os test.c,导致以下汇编程序:

    .file   "test.c"
    .text
    .globl  compare
    .type   compare, @function
compare:
.LFB24:
    .cfi_startproc
    xorl    %edx, %edx
.L2:
    movsbl  (%rdi,%rdx), %eax
    movsbl  (%rsi,%rdx), %ecx
    incq    %rdx
    cmpb    %cl, %al
    jne .L4
    testb   %al, %al
    jne .L2
.L4:
    subl    %ecx, %eax
    ret
    .cfi_endproc
.LFE24:
    .size   compare, .-compare
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC0:
    .string "bar"
.LC1:
    .string "foo"
    .section    .text.startup,"ax",@progbits
    .globl  main
    .type   main, @function
main:
.LFB25:
    .cfi_startproc
    movl    $.LC0, %esi
    movl    $.LC1, %edi
    call    compare
    movl    $1, %eax
    ret
    .cfi_endproc
.LFE25:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
    .section    .note.GNU-stack,"",@progbits

我在x86汇编程序中表现不佳,但据我所知,删除了对strcmp的调用,只需用常量表达式(movl $1, %eax)替换。因此,如果为测试使用常量表达式,gcc可能会将strcmp优化为常量。

答案 1 :(得分:5)

在比较性能时,我发现最好将测试函数和测试驱动程序放在不同的编译单元中。将测试函数放在单独的编译单元中,并将它们编译为您想要的任何优化级别,但编译未优化的测试驱动程序。否则你会遇到你在这里看到的那种问题。

问题是strcmp比较了两个const C风格的字符串。如果你在strcmp(string_a, string_b)上循环500,000,000次,那么优化编译器将足够聪明以减少该循环以优化该循环,然后可能足够智能以优化剩余的一个strcmp调用。

您的compare函数需要两个非const字符串。就编译器而言,您的功能可能会产生副作用。编译器不知道,因此无法将循环优化为零。它必须生成代码才能执行500,000,000次比较。

答案 2 :(得分:-1)

我相信大多数标准库都是用汇编语言编写的。这可能是您看到标准库比您的速度更快的原因。