我们的讲师解释说,这个函数可以计算字符串的长度......
int strlen_1(const char *str) {
const char *temp = str;
while(*temp != '\0') {
temp++;
}
return temp - str;
}
...会比这个更快地计算...
int strlen_03(const char *str) {
int i;
for (i = 0; *(str+i) != '\0'; i++);
return i;
我认为他说它与算术计算有关,就像在第一个任何算术计算完成时一样,但我无法理解,我看到它们都在同一级别。换句话说,你能解释一下原因吗?
PS。我理解指针,我可以理解发生了什么,就像是通过一个单元逐步存储到“RAM单元”中的数组元素。
提前致谢。
答案 0 :(得分:6)
暂时忽略优化,只看纸质算法:
前者重复执行此计算:
addr++
通过差异计算计算结果
addr1 - addr0
后者重复执行这些计算
addr0 + i
i++
结果由值返回
计算i
换句话说,在循环中完成了两倍的工作,以便在计算最终结果时做一半的工作。
进入优化的ASM,第一个在我的clang上生成-O3:
0x100000ee4: cmpb $0, 1(%rbx)
0x100000ee8: leaq 1(%rbx), %rbx
0x100000eec: sete %al
0x100000eef: testb $1, %al
0x100000ef1: je 0x100000ee4
第二个产生这个:
0x100000f09: incl %ebx
0x100000f0b: cmpb $0, (%rax)
0x100000f0e: leaq 1(%rax), %rax
0x100000f12: sete %cl
0x100000f15: testb $1, %cl
0x100000f18: je 0x100000f09
我遗漏了返回值的常数一次性因为它们不是循环复杂性的核心。优化器非常好,注意唯一的主要区别是单一:
0x100000f09: incl %ebx
这是您的i
答案 1 :(得分:5)
这是一个微优化,现代编译器最终可能会为两者生成相同的程序集,但对于非优化版本,原因如下:
int strlen_1(const char *str)
{
const char *temp = str; // declare the iterator
while(*temp != '\0') // dereference the pointer
// test the iterator
{
temp++; // increment the iterator
}
return temp - str; // pointer subtraction
}
对于长度为N的字符串,这将为您提供3N + 2次操作。
int strlen_03(const char *str)
{
int i; // declare your iterator
for (i = 0; *(str+i) != '\0'; i++); // initialize the iterator
// add i to str
// dereference that pointer value
// test it against \0
// increment i
return i;
}
对于相同的字符串,这将为您提供4N + 2次操作。
同样,现代编译器可能会为您解决此问题,即使在大多数字符串的未优化形式中,这个小循环也不太可能产生太大差异(仅适用于非常长串)。