memcpy () vs memmove ()
나는 차이를 이해하려고 memcpy()
하고 memmove()
, 나는 텍스트를 읽을 수있는 memcpy()
반면, 중복 소스의 관심과 대상을 고려하지 않습니다 memmove()
않습니다를.
그러나 겹치는 메모리 블록 에서이 두 기능을 실행하면 둘 다 동일한 결과를 얻습니다. 예를 들어, memmove()
도움말 페이지 에서 다음 MSDN 예제를 보자 .
의 단점을 이해하는 좋은 예 거기에 memcpy
어떻게 memmove
해결할 수있는 문제는?
// crt_memcpy.c
// Illustrate overlapping copy: memmove always handles it correctly; memcpy may handle
// it correctly.
#include <memory.h>
#include <string.h>
#include <stdio.h>
char str1[7] = "aabbcc";
int main( void )
{
printf( "The string: %s\n", str1 );
memcpy( str1 + 2, str1, 4 );
printf( "New string: %s\n", str1 );
strcpy_s( str1, sizeof(str1), "aabbcc" ); // reset string
printf( "The string: %s\n", str1 );
memmove( str1 + 2, str1, 4 );
printf( "New string: %s\n", str1 );
}
산출:
The string: aabbcc
New string: aaaabb
The string: aabbcc
New string: aaaabb
나는 당신의 모범이 이상한 행동을 보이지 않는다는 것에 완전히 놀랐습니다. 복사 시도 str1
로 str1+2
대신하고 어떻게되는지. (실제로 차이를 만들 수는 없으며 컴파일러 / 라이브러리에 따라 다릅니다.)
일반적으로 memcpy는 단순하지만 빠른 방식으로 구현됩니다. 간단히 말해서 데이터를 한 위치에서 다른 위치로 복사하여 순서대로 반복합니다. 이로 인해 소스를 읽는 동안 소스를 덮어 쓸 수 있습니다.
Memmove는 오버랩을 올바르게 처리하기 위해 더 많은 작업을 수행합니다.
편집하다:
(불행히도 괜찮은 예를 찾을 수는 없지만 그렇게 할 것입니다). 여기에 표시된 memcpy 및 memmove 구현을 대조 하십시오. memcpy는 루프 만하는 반면 memmove는 데이터 손상을 피하기 위해 루프 할 방향을 결정하는 테스트를 수행합니다. 이러한 구현은 다소 간단합니다. 대부분의 고성능 구현은 바이트가 아닌 한 번에 워드 크기 블록을 복사하는 것과 관련하여 더 복잡합니다.
메모리가 겹칠 memcpy
수 없거나 정의되지 않은 동작의 위험이있는 반면 메모리 memmove
가 겹칠 수 있습니다.
char a[16];
char b[16];
memcpy(a,b,16); // valid
memmove(a,b,16); // Also valid, but slower than memcpy.
memcpy(&a[0], &a[1],10); // Not valid since it overlaps.
memmove(&a[0], &a[1],10); // valid.
memcpy의 일부 구현은 여전히 겹치는 입력에 대해 작동 할 수 있지만 해당 동작을 계산할 수는 없습니다. memmove가 겹치는 것을 허용해야합니다.
그냥 있기 때문에 memcpy
중복 영역을 처리하지 않고, 올바르게 그들과 거래를하지 않는 것을 의미하지 않는다. 영역이 겹치는 호출은 정의되지 않은 동작을 생성합니다. 정의되지 않은 동작은 하나의 플랫폼에서 예상 한대로 작동 할 수 있습니다. 그것이 정확하거나 유효하다는 것을 의미하지는 않습니다.
memcpy와 memove는 비슷한 작업을 수행합니다.
그러나 한 가지 차이점을 알 수 있습니다.
#include <memory.h>
#include <string.h>
#include <stdio.h>
char str1[17] = "abcdef";
int main()
{
printf( "The string: %s\n", str1 );
memcpy( (str1+6), str1, 10 );
printf( "New string: %s\n", str1 );
strcpy_s( str1, sizeof(str1), "aabbcc" ); // reset string
printf( "The string: %s\n", str1 );
memmove( (str1+6), str1, 10 );
printf( "New string: %s\n", str1 );
}
제공합니다 :
The string: abcdef
New string: abcdefabcdefabcd
The string: abcdef
New string: abcdefabcdef
데모는 "나쁜"컴파일러로 인해 memcpy 단점을 노출하지 않았으므로 디버그 버전에서 유리합니다. 그러나 릴리스 버전은 동일한 출력을 제공하지만 최적화 때문입니다.
memcpy(str1 + 2, str1, 4);
00241013 mov eax,dword ptr [str1 (243018h)] // load 4 bytes from source string
printf("New string: %s\n", str1);
00241018 push offset str1 (243018h)
0024101D push offset string "New string: %s\n" (242104h)
00241022 mov dword ptr [str1+2 (24301Ah)],eax // put 4 bytes to destination
00241027 call esi
여기서 레지스터 %eax
는 임시 저장소로 재생되며 겹치는 문제를 "우아하게"수정합니다.
6 바이트를 복사 할 때 적어도 일부는 복사 할 때 단점이 발생합니다.
char str1[9] = "aabbccdd";
int main( void )
{
printf("The string: %s\n", str1);
memcpy(str1 + 2, str1, 6);
printf("New string: %s\n", str1);
strcpy_s(str1, sizeof(str1), "aabbccdd"); // reset string
printf("The string: %s\n", str1);
memmove(str1 + 2, str1, 6);
printf("New string: %s\n", str1);
}
산출:
The string: aabbccdd
New string: aaaabbbb
The string: aabbccdd
New string: aaaabbcc
이상하게 보입니다. 최적화 때문이기도합니다.
memcpy(str1 + 2, str1, 6);
00341013 mov eax,dword ptr [str1 (343018h)]
00341018 mov dword ptr [str1+2 (34301Ah)],eax // put 4 bytes to destination, earlier than the above example
0034101D mov cx,word ptr [str1+4 (34301Ch)] // HA, new register! Holding a word, which is exactly the left 2 bytes (after 4 bytes loaded to %eax)
printf("New string: %s\n", str1);
00341024 push offset str1 (343018h)
00341029 push offset string "New string: %s\n" (342104h)
0034102E mov word ptr [str1+6 (34301Eh)],cx // Again, pulling the stored word back from the new register
00341035 call esi
이것이 memmove
2 개의 겹친 메모리 블록을 복사하려고 할 때 항상 선택하는 이유 입니다.
차이 memcpy
하고 memmove
있다는 것이다
에서
memmove
지정된 크기의 소스 메모리가 버퍼에 복사 된 다음 대상으로 이동됩니다. 따라서 메모리가 겹치는 경우 부작용이 없습니다.in case of
memcpy()
, there is no extra buffer taken for source memory. The copying is done directly on the memory so that when there is memory overlap, we get unexpected results.
These can be observed by the following code:
//include string.h, stdio.h, stdlib.h
int main(){
char a[]="hare rama hare rama";
char b[]="hare rama hare rama";
memmove(a+5,a,20);
puts(a);
memcpy(b+5,b,20);
puts(b);
}
Output is:
hare hare rama hare rama
hare hare hare hare hare hare rama hare rama
As already pointed out in other answers, memmove
is more sophisticated than memcpy
such that it accounts for memory overlaps. The result of memmove is defined as if the src
was copied into a buffer and then buffer copied into dst
. This does NOT mean that the actual implementation uses any buffer, but probably does some pointer arithmetic.
compiler could optimize memcpy, for example:
int x;
memcpy(&x, some_pointer, sizeof(int));
This memcpy may be optimized as: x = *(int*)some_pointer;
The code given in the links http://clc-wiki.net/wiki/memcpy for memcpy seems to confuse me a bit, as it does not give the same output when I implemented it using the below example.
#include <memory.h>
#include <string.h>
#include <stdio.h>
char str1[11] = "abcdefghij";
void *memcpyCustom(void *dest, const void *src, size_t n)
{
char *dp = (char *)dest;
const char *sp = (char *)src;
while (n--)
*dp++ = *sp++;
return dest;
}
void *memmoveCustom(void *dest, const void *src, size_t n)
{
unsigned char *pd = (unsigned char *)dest;
const unsigned char *ps = (unsigned char *)src;
if ( ps < pd )
for (pd += n, ps += n; n--;)
*--pd = *--ps;
else
while(n--)
*pd++ = *ps++;
return dest;
}
int main( void )
{
printf( "The string: %s\n", str1 );
memcpy( str1 + 1, str1, 9 );
printf( "Actual memcpy output: %s\n", str1 );
strcpy_s( str1, sizeof(str1), "abcdefghij" ); // reset string
memcpyCustom( str1 + 1, str1, 9 );
printf( "Implemented memcpy output: %s\n", str1 );
strcpy_s( str1, sizeof(str1), "abcdefghij" ); // reset string
memmoveCustom( str1 + 1, str1, 9 );
printf( "Implemented memmove output: %s\n", str1 );
getchar();
}
Output :
The string: abcdefghij
Actual memcpy output: aabcdefghi
Implemented memcpy output: aaaaaaaaaa
Implemented memmove output: aabcdefghi
But you can now understand why memmove will take care of overlapping issue.
C11 standard draft
The C11 N1570 standard draft says:
7.24.2.1 "The memcpy function":
2 The memcpy function copies n characters from the object pointed to by s2 into the object pointed to by s1. If copying takes place between objects that overlap, the behavior is undefined.
7.24.2.2 "The memmove function":
2 The memmove function copies n characters from the object pointed to by s2 into the object pointed to by s1. Copying takes place as if the n characters from the object pointed to by s2 are first copied into a temporary array of n characters that does not overlap the objects pointed to by s1 and s2, and then the n characters from the temporary array are copied into the object pointed to by s1
Therefore, any overlap on memcpy
leads to undefined behavior, and anything can happen: bad, nothing or even good. Good is rare though :-)
memmove
however clearly says that everything happens as if an intermediate buffer is used, so clearly overlaps are OK.
C++ std::copy
is more forgiving however, and allows overlaps: Does std::copy handle overlapping ranges?
I have tried to run same program using eclipse and it shows clear difference between memcpy
and memmove
. memcpy()
doesn't care about overlapping of memory location which results in corruption of data, while memmove()
will copy data to temporary variable first and then copy into actual memory location.
While trying to copy data from location str1
to str1+2
, output of memcpy
is "aaaaaa
". The question would be how? memcpy()
will copy one byte at a time from left to right. As shown in your program "aabbcc
" then all copying will take place as below,
aabbcc -> aaabcc
aaabcc -> aaaacc
aaaacc -> aaaaac
aaaaac -> aaaaaa
memmove()
will copy data to temporary variable first and then copy to actual memory location.
aabbcc(actual) -> aabbcc(temp)
aabbcc(temp) -> aaabcc(act)
aabbcc(temp) -> aaaacc(act)
aabbcc(temp) -> aaaabc(act)
aabbcc(temp) -> aaaabb(act)
Output is
memcpy
: aaaaaa
memmove
: aaaabb
참고URL : https://stackoverflow.com/questions/4415910/memcpy-vs-memmove
'IT' 카테고리의 다른 글
신호로 인해 명령이 실패했습니다 : 분할 오류 : 11 (0) | 2020.06.15 |
---|---|
SHA-1은 암호 저장에 안전합니까? (0) | 2020.06.15 |
특정 https 원격에 대한 특정 자체 서명 서버 인증서를 수락하도록 Git 구성 (0) | 2020.06.15 |
내용과 정확히 일치하는 요소를 선택하십시오. (0) | 2020.06.15 |
Rails에서 무언가를 독립적 인 로그 파일로 기록하는 방법은 무엇입니까? (0) | 2020.06.15 |