strstr函数的效率为什么那么高?
关注者
7被浏览
9,2472 个回答
简要答案:
因为你没利用strstr的返回值,这个函数根本就没被调用。而编译器不敢优化你自己写的函数。
具体过程:
我们来进行一下测试:
1. g++ 5.3.0, Linux x64
编译选项:g++ -g -o test test.cpp
运行结果:
➜ ~ git:(master) ✗ ./test
0
1
➜ ~ git:(master) ✗ ./test
0
1
➜ ~ git:(master) ✗ ./test
1
0
➜ ~ git:(master) ✗ ./test
0
1
➜ ~ git:(master) ✗ ./test
0
1
➜ ~ git:(master) ✗ ./test
1
0
➜ ~ git:(master) ✗ ./test
0
1
➜ ~ git:(master) ✗ ./test
1
0
总体来说,两者速度差不多
反汇编看看:
objdump -dS test
test函数调用:
int start_t, end_t, i;
start_t = time(NULL);
4008bd: bf 00 00 00 00 mov $0x0,%edi
4008c2: e8 89 fe ff ff callq 400750 <time@plt>
4008c7: 89 45 f8 mov %eax,-0x8(%rbp)
for( i = 0; i < 200000000; i++)
4008ca: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
4008d1: 81 7d fc ff c1 eb 0b cmpl $0xbebc1ff,-0x4(%rbp)
4008d8: 7f 19 jg 4008f3 <main+0x67> //比较,>=200000000 则跳出循环
{
test(src, des);
4008da: 48 8d 55 d0 lea -0x30(%rbp),%rdx //可以看出,这里对test的调用是通过寄存器传值的,用了一个call,需要压栈
4008de: 48 8d 45 e0 lea -0x20(%rbp),%rax
4008e2: 48 89 d6 mov %rdx,%rsi
4008e5: 48 89 c7 mov %rax,%rdi
4008e8: e8 69 ff ff ff callq 400856 <_Z4testPKcS0_>
char src[] = "GCGCBGGAGTCAGAe";
char des[] = "CAGAG";
int start_t, end_t, i;
start_t = time(NULL);
for( i = 0; i < 200000000; i++)
4008ed: 83 45 fc 01 addl $0x1,-0x4(%rbp)
4008f1: eb de jmp 4008d1 <main+0x45> //进行下一轮循环
{
test(src, des);
}
end_t = time(NULL);
4008f3: bf 00 00 00 00 mov $0x0,%edi //结束循环
4008f8: e8 53 fe ff ff callq 400750 <time@plt>
而strstr:
start_t = time(NULL);
40091f: bf 00 00 00 00 mov $0x0,%edi
400924: e8 27 fe ff ff callq 400750 <time@plt>
400929: 89 45 f8 mov %eax,-0x8(%rbp)
for( i = 0; i < 200000000; i++) // 这里根本就没有strstr相关的调用,因为被优化掉了
40092c: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
400933: 81 7d fc ff c1 eb 0b cmpl $0xbebc1ff,-0x4(%rbp)
40093a: 7f 06 jg 400942 <main+0xb6>
40093c: 83 45 fc 01 addl $0x1,-0x4(%rbp)
400940: eb f1 jmp 400933 <main+0xa7>
{
strstr(src, des);
}
end_t = time(NULL);
400942: bf 00 00 00 00 mov $0x0,%edi
400947: e8 04 fe ff ff callq 400750 <time@plt>
40094c: 89 45 f4 mov %eax,-0xc(%rbp)
总结:因为你的test函数基本都是寄存器操作,所以耗时也很少。而strstr根本就没被调用,所以两者速度差不多,
2. clang++ 3.7
编译选项:
clang++ -g -o test test.cpp
运行结果:
➜ ~ git:(master) ✗ ./test
0
2
➜ ~ git:(master) ✗ ./test
0
2
➜ ~ git:(master) ✗ ./test
0
2
有了明显差距。
看一看反汇编:
objdump -dS test
start_t = time(NULL);
400a18: 48 89 45 c0 mov %rax,-0x40(%rbp)
400a1c: e8 7f fd ff ff callq 4007a0 <time@plt>
400a21: 89 c1 mov %eax,%ecx
400a23: 89 4d d4 mov %ecx,-0x2c(%rbp)
for( i = 0; i < 200000000; i++)
400a26: c7 45 cc 00 00 00 00 movl $0x0,-0x34(%rbp)
400a2d: 81 7d cc 00 c2 eb 0b cmpl $0xbebc200,-0x34(%rbp)
400a34: 0f 8d 1f 00 00 00 jge 400a59 <main+0xf9>
400a3a: 48 8d 75 da lea -0x26(%rbp),%rsi
400a3e: 48 8d 7d e0 lea -0x20(%rbp),%rdi
{
strstr(src, des);
400a42: e8 59 00 00 00 callq 400aa0 <_ZSt6strstrPcPKc>
// 不出所料,发生了调用
400a47: 48 89 45 b8 mov %rax,-0x48(%rbp)
}
end_t = time(NULL);
cout<<end_t - start_t<<endl;
start_t = time(NULL);
for( i = 0; i < 200000000; i++)
400a4b: 8b 45 cc mov -0x34(%rbp),%eax