理论上两种方法中哪一种更快,为什么?(指向字符串的指针必须是常量.)
destination [count]和*destination ++之间的确切区别是什么?目的地[count]是否会在每次通话时从0移动到计数?*destination ++只是在每次通话时加1吗?
char *const string = "Hello world!";
char *destination = malloc(strlen(string) + 1);
int count = 0;
while(string[count] != '\0')
{
destination[count] = string[count];
count++;
}
char *const string = "Hello world!";
char *destination = malloc(strlen(string) + 1);
char *ptr = string;
while(*ptr != '\0')
{
*destination++ = *ptr++;
}
Run Code Online (Sandbox Code Playgroud)
这取决于编译器.使用现代编译器,实际上无法在单指令级别上预测任何有关优化的内容,而无需实际查看生成的代码.两者都可能编译为等效指令.
也就是说,每次调用destination[count]都不会从0循环到count每次调用.它需要内存位置destination[0],增加count类型大小的时间*destination,并在那里查看.(当然,这很天真地说 - 编译器可能会做得更快.)
在另一方面,*destination++需要的存储位置destination[0](这是不是数组的开始了,因为你已经改变destination),看上去那里,并添加类型的大小*destination,使destination[0]指的是什么曾经是destination[1].
在过去的好时光,第二种方法更快.但是使用现代编译器优化,它们是一样的.
这是因为:
destination[count] = string[count];
Run Code Online (Sandbox Code Playgroud)
会做的
*(destination+count) = *(string+count);
Run Code Online (Sandbox Code Playgroud)
add每个循环需要再操作两次.现代编译器会为你做这件事.
我们为什么要推测?我们可以尝试并找出答案.我用gcc -O3 -g(在x86上)编译代码并反汇编结果.有比我预期的更多的变化,所以我将集中在中间的位置,我们期望两者之间的大部分差异.第一种情况下循环的核心:
0x00000030 <foo+48>: mov %dl,(%edi,%esi,1)
0x00000033 <foo+51>: movzbl 0x1(%ecx),%edx
0x00000037 <foo+55>: inc %eax
0x00000038 <foo+56>: inc %ecx
0x00000039 <foo+57>: mov %eax,%esi
0x0000003b <foo+59>: test %dl,%dl
0x0000003d <foo+61>: jne 0x30 <foo+48>
Run Code Online (Sandbox Code Playgroud)
第二种情况下循环的核心:
0x00000080 <foo2+48>: mov %dl,(%eax)
0x00000082 <foo2+50>: movzbl 0x1(%ecx),%edx
0x00000086 <foo2+54>: inc %eax
0x00000087 <foo2+55>: inc %ecx
0x00000088 <foo2+56>: test %dl,%dl
0x0000008a <foo2+58>: jne 0x80 <foo2+48>
Run Code Online (Sandbox Code Playgroud)
在此基础上,第二个可能会快一点.但实际上,它在实践中不会产生太大的影响.L1缓存保持两个循环都很好,目标内存未缓存,因此差异没有实际意义.祝你好好实际测量两者之间的差异.