memcpy() vs memmove()
나는 와의 차이를 이해하려고 노력하고 있으며, 나는 다음과 같은 텍스트를 읽었다.memcpy()는, doesn는송 doesn doesn doesn doesn doesn doesn doesn doesn doesn doesn doesn doesn 。memmove()
그러나 중복되는 메모리 블록에서 이 두 가지 기능을 실행하면 둘 다 같은 결과를 얻을 수 있습니다.를 들어, MSDN의 다음 들 수 .memmove() 페이지 - 움말- : -
의 하기 위한 더 요?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중복되는 지역을 처리할 필요가 없습니다.그렇다고 해서, 그것들을 올바르게 처리하지 않는 것은 아닙니다.리젼이 중복된 콜에서는 정의되지 않은 동작이 발생합니다.정의되지 않은 동작은 하나의 플랫폼에서 완전히 예상대로 동작할 수 있습니다.그렇다고 해서 그것이 올바르거나 유효한 것은 아닙니다.
C11 표준 드래프트
C11 N1570 표준 초안에는 다음과 같이 기재되어 있습니다.
7.24.2.1 "memcpy 기능":
2 memcpy 함수는 s2가 가리키는 오브젝트에서 s1이 가리키는 오브젝트로 n개의 문자를 복사합니다.중복되는 객체 간에 복사가 이루어지는 경우 동작은 정의되지 않습니다.
7.24.2.2 "멤무브 기능":
2 memmove 함수는 s2가 가리키는 오브젝트에서 s1이 가리키는 오브젝트로 n개의 문자를 복사합니다.복사는 s2가 가리키는 오브젝트로부터의 n문자를 s1과 s2가 가리키는 오브젝트와 겹치지 않는n문자의 임시배열로 먼저 복사한 후 s1이 가리키는 오브젝트로 복사하는 것으로 이루어진다.
따라서, 에 중복되는 것은memcpy정의되지 않은 행동을 하게 되고, 어떤 일이든 일어날 수 있습니다. 나쁜 일, 나쁜 일, 좋은 일, 심지어 좋은 일까지요.좋은 것은 드물지만 :-)
memmove단, 모든 것이 중간 버퍼를 사용하는 것처럼 발생하므로 중복이 명확하게 발생해도 괜찮습니다.
C++std::copy단, 보다 관대하고 중복이 허용됩니다.std::copy 핸들 오버랩 범위입니까?
데모에서는 "불량" 컴파일러로 인해 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와 memove는 모두 비슷한 일을 합니다.
하지만 한 가지 차이점을 발견하려면:
#include <memory.h>
#include <string.h>
#include <stdio.h>
char str1[7] = "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("\nstr1: %s\n", str1);
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그리고.memmove그것이다
에
memmove지정된 크기의 소스 메모리가 버퍼에 복사되어 수신처로 이동합니다.그래서 메모리가 겹치면 부작용이 없어요.만일의 경우
memcpy()소스 메모리에 추가 버퍼는 없습니다.메모리상에서 직접 카피가 행해지므로, 메모리가 오버랩 되었을 때에 예기치 않은 결과를 얻을 수 있습니다.
이것들은, 다음의 코드로 확인할 수 있습니다.
//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);
}
출력:
hare hare rama hare rama
hare hare hare hare hare hare rama hare rama
이클립스를 사용하여 동일한 프로그램을 실행하려고 시도했는데, 이클립스 간에 명확한 차이가 있습니다.memcpy그리고.memmove.memcpy()메모리 위치가 중복되어 데이터가 파손되어도 상관없습니다.memmove()는 먼저 데이터를 임시변수에 복사한 후 실제 메모리 위치에 복사합니다.
에서 할 때str1로로 합니다.str1+2의, " "memcpy 「 」입니다.aaaaaa는 어떻게?"입니다. 문제는 어떻게 하냐는 거죠. memcpy()는 한 번에 1바이트씩 왼쪽에서 오른쪽으로 복사합니다.프로그램에 나타난 바와 같이"aabbcc 모든 는 아래와
aabbcc -> aaabccaaabcc -> aaaaccaaaacc -> aaaaacaaaaac -> aaaaaa
memmove()는 먼저 데이터를 임시변수에 복사한 후 실제 메모리 위치에 복사합니다.
aabbcc(actual) -> aabbcc(temp)aabbcc(temp) -> aaabcc(act)aabbcc(temp) -> aaaacc(act)aabbcc(temp) -> aaaabc(act)aabbcc(temp) -> aaaabb(act)
출력은
memcpyaaaaaa
memmoveaaaabb
다른 답변에서도 이미 지적했듯이memmove되어 있다memcpy★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★는 memmove의 경우와 됩니다.src되었습니다.dst이는 실제 구현에서 버퍼를 사용하는 것은 아니지만 포인터 계산을 수행할 수 있습니다.
컴파일러는 다음과 같이 memcpy를 최적화할 수 있습니다.
int x;
memcpy(&x, some_pointer, sizeof(int));
는 다음과 같이 할 수 .memcpy는 memcpy로 최적화할 수 있습니다.x = *(int*)some_pointer;
memcpy의 링크 http://clc-wiki.net/wiki/memcpy에 표시된 코드는 다음 예시를 사용하여 구현했을 때 동일한 출력을 제공하지 않기 때문에 약간 혼란스러운 것 같습니다.
#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();
}
출력:
The string: abcdefghij
Actual memcpy output: aabcdefghi
Implemented memcpy output: aaaaaaaaaa
Implemented memmove output: aabcdefghi
그러나 이제 memmove가 중복되는 문제를 처리하는 이유를 알 수 있습니다.
언급URL : https://stackoverflow.com/questions/4415910/memcpy-vs-memmove
'programing' 카테고리의 다른 글
| 어레이 또는 중첩된 데이터가 포함된 Vuex 양방향 계산 속성 (0) | 2022.08.07 |
|---|---|
| Vuex 스토어에서 JWT 토큰을 새로 고친 후 Axios를 사용하여 요청 재시도 (0) | 2022.08.07 |
| Java에서의 RESTful 콜 (0) | 2022.08.07 |
| C#에서 C 함수를 호출할 수 있습니까?그물 (0) | 2022.08.07 |
| 현재 vue 구성 요소의 메서드를 기본 프로펠러 값으로 사용 (0) | 2022.08.07 |