先说答案,不一定。
事情是这样的,我在写操作系统,看到田宇大佬写的代码里面,strlen也是用汇编来写的,我很不解,这个不是可以用C来实现吗?难不成纯汇编更快?于是我就写了一个小程序来做实验。看看这两者的速度。
这个程序首先是随机生成了1E6长度的字符串,然后分别进行1000次计算大小,可以发现,C语言的函数运行的更快一些些。
//测试strlen的速度
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
int n = 1e6; //生成长度为1e6的字符串
char s[1000007];
void generate_string()
{
//先删除s
srand((unsigned)time(NULL));
for (size_t i = 0; i < n; i++)
{
/* code */
s[i] = 'a' + rand() % 26;
}
s[n] = '\0';
}
int _strlen_asm(char *s)
{
register int __res;
__asm__ __volatile__("cld \n\t"
"repne \n\t"
"scasb \n\t"
"notl %0 \n\t"
"decl %0 \n\t"
: "=c"(__res)
: "D"(s), "a"(0), "0"(0xffffffff)
:);
return __res;
}
int _strlen_c(char *s)
{
register int __res = 0;
while (s[__res] != '\0')
{
++__res;
}
return __res;
}
int main()
{
generate_string();
time_t start, end;
clock_t total_asm = 0;
int times = 1000;
for (int i = 0; i < times; ++i)
{
start = clock();
_strlen_asm(s);
total_asm += clock()-start;
}
printf("%lf\n", 1.0*total_asm/times);
clock_t total_c = 0;
for (int i = 0; i < times; ++i)
{
start = clock();
_strlen_c(s);
total_c += clock()-start;
}
printf("%lf\n", 1.0*total_c/times);
}
运行速度:
田宇大佬的汇编版本:平均517.047000ms
C语言版本:平均430.027000ms
可以看到C版本的运行的更快,快了16.8%。
考虑到可能是这两个函数执行先后性的影响,交换一下他们的先后顺序,得到的结果依然不变。
怀着疑问,再来看看他们编译后的汇编代码:也许jmp指令对于处理器的分支预测更友好?
00000000004011de <_strlen_asm>:
4011de: 55 push %rbp
4011df: 48 89 e5 mov %rsp,%rbp
4011e2: 53 push %rbx
4011e3: 48 89 7d f0 mov %rdi,-0x10(%rbp)
4011e7: 48 8b 75 f0 mov -0x10(%rbp),%rsi
4011eb: b8 00 00 00 00 mov $0x0,%eax
4011f0: ba ff ff ff ff mov $0xffffffff,%edx
4011f5: 89 d1 mov %edx,%ecx
4011f7: 48 89 f7 mov %rsi,%rdi
4011fa: fc cld
4011fb: f2 ae repnz scas %es:(%rdi),%al
4011fd: f7 d1 not %ecx
4011ff: ff c9 dec %ecx
401201: 89 ca mov %ecx,%edx
401203: 89 d3 mov %edx,%ebx
401205: 89 d8 mov %ebx,%eax
401207: 5b pop %rbx
401208: 5d pop %rbp
401209: c3 ret
000000000040120a <_strlen_c>:
40120a: 55 push %rbp
40120b: 48 89 e5 mov %rsp,%rbp
40120e: 53 push %rbx
40120f: 48 89 7d f0 mov %rdi,-0x10(%rbp)
401213: bb 00 00 00 00 mov $0x0,%ebx
401218: eb 03 jmp 40121d <_strlen_c+0x13>
40121a: 83 c3 01 add $0x1,%ebx
40121d: 48 63 d3 movslq %ebx,%rdx
401220: 48 8b 45 f0 mov -0x10(%rbp),%rax
401224: 48 01 d0 add %rdx,%rax
401227: 0f b6 00 movzbl (%rax),%eax
40122a: 84 c0 test %al,%al
40122c: 75 ec jne 40121a <_strlen_c+0x10>
40122e: 89 d8 mov %ebx,%eax
401230: 5b pop %rbx
401231: 5d pop %rbp
401232: c3 ret
转载请注明来源:https://longjin666.cn/?p=1329
欢迎关注我的公众号“灯珑”,让我们一起了解更多的事物~