Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;memcpy函数,为什么使用*s++;而不是s[i]_C++_Memcpy - Fatal编程技术网

C++ C++;memcpy函数,为什么使用*s++;而不是s[i]

C++ C++;memcpy函数,为什么使用*s++;而不是s[i],c++,memcpy,C++,Memcpy,我从头开始编写memcpy,并一直在查找其他人的实现……我的实现是: void* memcpy (void *destination, const void *source, size_t num) { char *D = (char*)destination; char *S = (char*)source; for(int i = 0; i < num; i++) D[i] = S[i]; return D; } void*me

我从头开始编写memcpy,并一直在查找其他人的实现……我的实现是:

void* memcpy (void *destination, const void *source, size_t num)
{
    char *D = (char*)destination;
    char *S = (char*)source;
    for(int i = 0; i < num; i++)
            D[i] = S[i];
    return D;
}
void*memcpy(void*destination,const void*source,size\u t num)
{
char*D=(char*)目的地;
char*S=(char*)源;
for(int i=0;i
我研究过的各种其他来源和参考文献

void* memcpy (void *destination, const void *source, size_t num)
{
    char *D = (char*)destination;
    char *S = (char*)source;
    for(int i = 0; i < num; i++) 
    {
            *D = *S;
            D++;
            S++;
    }
    return D;
}
void*memcpy(void*destination,const void*source,size\u t num)
{
char*D=(char*)目的地;
char*S=(char*)源;
for(int i=0;i

我很难理解这种差异以及它们是否会产生不同的输出。让我特别困惑的部分是D++;和S++

现代编译器将对这些代码进行优化,以获得相同的代码。这被称为强度降低。(除了不同的返回值。)

D++
S++
正在递增指针

请记住,
D[i]
相当于
*(D+i)

因此,一个是递增指针,另一个是保持基数并添加偏移量

现代编译器可能会编译成相同的代码


注意:我假设
返回D是复制粘贴错误,因为它应该是
返回目的地因为
D
是递增的,并指向内存“after”目标字节

编写此代码时,避免向指针添加索引可能会更快


在我自己对x86体系结构的测试中,该体系结构在底层指令中内置了索引模式,索引方法稍微快一些。

算法是等效的。第二个版本使用将指针前进到下一个位置,而不是使用
a[i]
语法索引数组


这是因为
a[i]
实际上是
*(a+i)
的简写(读:advance
i
定位在
a
之前,并读取该位置的值)。它不是在每次迭代时执行总偏移量(
+i
),而是在每次迭代时执行部分偏移量(
+a
),并累加结果。

虽然两者在语义上的意思相同,
*s++
版本将避免在复制数组的字节中递增时偏移初始指针值。换句话说,
s[i]
的“底层”表示实际上是
*(s+i*sizeof(type))
,并且乘法,尤其是
i
的大值的乘法,比简单的小值增量要慢得多,至少取决于机器结构


但最终,
memcpy
libc
实现将比用C编写的任何东西都要快得多,因为使用了依赖于机器的优化内存复制汇编指令,您无法通过普通C代码故意访问这些指令。

让您困惑的是指针算法:
D++
S++
。指针正在递增,以引用下一个
char
(正如它们是
char*

以下是由GCC编译的内部循环。我刚刚添加了
restrict
关键字,删除了返回值,并为Core 2编译了32位:

第一个,数组版本:

.L3:
  movzbl  (%edi,%edx), %ecx
  addl    $1, %eax  
  cmpl    %ebx, %eax
  movb    %cl, (%esi,%edx)
  movl    %eax, %edx
  jne .L3
第二,增量版本:

.L9:
  movzbl  (%edx), %ebx
  addl    $1, %ecx   
  addl    $1, %edx   
  movb    %bl, (%eax)
  addl    $1, %eax  
  cmpl    %ecx, %esi
  ja  .L9

正如您所看到的,编译器正确地看穿了这两种结构。

尽管这两种方式都没有什么区别,但看到这两种情况我会有点惊讶。我希望有更接近于:

void* memcpy (void *destination, const void *source, size_t num) {
    char *S = (char *)source;
    char *D = (char *)destination;
    while (--num)
        *D++ = *S++;
    return destination;
}

不管怎样,大多数优秀的编译器都会生成大致相同的代码。我最近没有检查过,但有一段时间,大多数针对x86的编译器都会将大部分循环转换为一条
rep movsd
指令。不过,它们可能不再是——这不再是最优的。

随机注释:您应该声明
i
size\u t
not
int
Random note 2:第二个版本返回不同的指针值。随机注释3:使用自定义
memcpy
,您永远不会获得更好的性能。嗯,至少99%的情况下不需要,也许更多。问题的可能重复随机注4:在第二个片段中,你不需要i。只是(当num--)*D++=*S++;返回目的地;不,不是,应该是D+i*sizeof(char)。如果编译器不优化乘法,则乘法将比指针中的加法慢得多increment@Rado由于
sizeof(char)
始终为1,因此没有区别。<代码> SigeOS/<代码>操作符返回字符大小。@ RADO实际上是<代码> D+I < /CUT>两个原因:1,C++做指针算术,2,<代码> siZeOf(char)=1</COD>总是,所以即使C++没有做指针算术,也将是<代码> D+I < /代码>。但是他忘记了<代码> */COD> > RADO:C++中的指针算术已经包含了数组中的元素<代码> > t>代码>的<代码> sieOf(t)< /c>乘法。@拉多,它不是<代码> d+i*sieOf(char)< /C>。事实上,我忘记了刚才添加的
*
。感谢您指出。事实上,AFAIKx86对索引数组有特殊的说明。如果处理器管道看到这些指令,那么它可能会执行更高效的缓存。再说一遍,这真的取决于编译器生成的机器指令。你真的测试过这个吗?通过简单地使用指针而不是使用索引来访问指针,我已经使一段代码的效率提高了很多。然而,我已经在一个编译器中实现了这个精确的优化。这是众所周知的。如果两个函数都被修改为不返回任何内容,大多数编译器将生成相同的(或实际上相同的)结果