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

Enr*_*Fan 20 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;
}
Run Code Online (Sandbox Code Playgroud)

该函数的执行时间3.058s,而strcmp0.004s.

为什么会这样?

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

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

编辑:测试我编写的一些代码和优化,提高了Str::Compare速度.如果之前strcmpx750倍,现在只有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;
}
Run Code Online (Sandbox Code Playgroud)

新的执行时间是0.994s.

lwi*_*lwi 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;
}
Run Code Online (Sandbox Code Playgroud)

gcc -S -Os test.c使用gcc 4.7.3将它编译成汇编程序,产生以下汇编程序:

    .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
Run Code Online (Sandbox Code Playgroud)

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

  • [这里是G ++ 4.8.1将所有内容减少到Coliru的常量.](http://coliru.stacked-crooked.com/a/8bec7ba91e5fce00) (4认同)

Dav*_*men 5

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

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

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