memmove
과 의 차이점은 무엇입니까 memcpy
? 일반적으로 어떤 것을 사용하고 어떻게 사용합니까?
답변
를 사용 memcpy
하면 대상이 소스와 전혀 겹칠 수 없습니다. 로 memmove
가 있습니다. 이는 다음 memmove
보다 약간 느릴 수 있음을 의미합니다.memcpy
동일한 가정을 할 수 없기 때문에 .
예를 들어 memcpy
는 항상 낮은 주소에서 높은 주소로 주소를 복사 할 수 있습니다. 대상이 소스 뒤에 겹치는 경우 복사하기 전에 일부 주소를 덮어 쓰게됩니다. memmove
이 경우이를 감지하고 다른 방향 (높은 방향에서 낮은 방향으로)으로 복사합니다. 그러나 이것을 확인하고 다른 알고리즘으로 전환하는 데 시간이 걸립니다.
답변
memmove
겹치는 메모리를 처리 할 수 있습니다. memcpy
할 수 있습니다.
치다
char[] str = "foo-bar";
memcpy(&str[3],&str[4],4); //might blow up
분명히 소스와 대상이 겹칩니다. “-bar”를 “bar”로 덮어 씁니다. memcpy
소스와 대상이 겹치는 경우를 사용 하는 정의되지 않은 동작이므로이 경우에는 memmove
.
memmove(&str[3],&str[4],4); //fine
답변
로부터 방어 적이기 매뉴얼 페이지를 참조하십시오.
memcpy () 함수는 src 메모리 영역에서 dest 메모리 영역으로 n 바이트를 복사합니다. 메모리 영역은 겹치지 않아야합니다. 메모리 영역이 겹치는 경우 memmove (3)를 사용하십시오 .
답변
주요 차이점 memmove()
과 memcpy()
에 있다는 것이다 버퍼 임시 메모리 – – 사용되므로 중첩의 위험이 없다. 반면에 의해 지시되는 위치에서 직접적으로 데이터를 복사하는 소스 위치로가 가리키는 도착 . ( http://www.cplusplus.com/reference/cstring/memcpy/memmove()
memcpy()
)
다음 예를 고려하십시오.
-
#include <stdio.h> #include <string.h> int main (void) { char string [] = "stackoverflow"; char *first, *second; first = string; second = string; puts(string); memcpy(first+5, first, 5); puts(first); memmove(second+5, second, 5); puts(second); return 0; }
예상대로 다음과 같이 인쇄됩니다.
stackoverflow stackstacklow stackstacklow
-
그러나이 예에서는 결과가 동일하지 않습니다.
#include <stdio.h> #include <string.h> int main (void) { char string [] = "stackoverflow"; char *third, *fourth; third = string; fourth = string; puts(string); memcpy(third+5, third, 7); puts(third); memmove(fourth+5, fourth, 7); puts(fourth); return 0; }
산출:
stackoverflow stackstackovw stackstackstw
“memcpy ()”는 다음을 수행하기 때문입니다.
1. stackoverflow
2. stacksverflow
3. stacksterflow
4. stackstarflow
5. stackstacflow
6. stackstacklow
7. stackstacksow
8. stackstackstw
답변
둘 다 구현해야한다고 가정하면 구현은 다음과 같을 수 있습니다.
void memmove ( void * dst, const void * src, size_t count ) {
if ((uintptr_t)src < (uintptr_t)dst) {
// Copy from back to front
} else if ((uintptr_t)dst < (uintptr_t)src) {
// Copy from front to back
}
}
void mempy ( void * dst, const void * src, size_t count ) {
if ((uintptr_t)src != (uintptr_t)dst) {
// Copy in any way you want
}
}
그리고 이것은 그 차이를 꽤 잘 설명 할 것입니다. memmove
이 경우 안전 여전히 것과 같은 방식으로 항상 사본 src
및 dst
중복 반면, memcpy
사용할 때 문서가 말한대로 그냥 상관하지 않는다 memcpy
두 개의 메모리 영역이 되지해야합니다 중복.
예를 들어 memcpy
“앞에서 뒤로”복사하고 메모리 블록이 이렇게 정렬 된 경우
[---- src ----]
[---- dst ---]
의 첫 번째 바이트 복사 src
에 dst
의 마지막 바이트의 내용은 이미 파괴src
이 복사되기 전에를. “뒤에서 앞으로”만 복사하면 올바른 결과를 얻을 수 있습니다.
이제 스왑 src
및 dst
:
[---- dst ----]
[---- src ---]
이 경우 “앞에서 뒤로”복사하면 “앞에서 뒤로”복사하는 것이 안전합니다. src
복사하면 첫 번째 바이트를 복사 할 때 이미 앞쪽 근처 되기 때문입니다.
memmove
위 의 구현은 실제로 겹치는 지 테스트하지 않고 상대 위치 만 확인하지만 그만으로도 복사본을 안전하게 만들 수 있습니다. 로서 memcpy
일반적으로 모든 시스템에 메모리를 복사 할 수있는 가장 빠른 방법을 사용하여, memmove
일반적으로 오히려으로 구현됩니다 :
void memmove ( void * dst, const void * src, size_t count ) {
if ((uintptr_t)src < (uintptr_t)dst
&& (uintptr_t)src + count > (uintptr_t)dst
) {
// Copy from back to front
} else if ((uintptr_t)dst < (uintptr_t)src
&& (uintptr_t)dst + count > (uintptr_t)src
) {
// Copy from front to back
} else {
// They don't overlap for sure
memcpy(dst, src, count);
}
}
경우에 따라 memcpy
항상 “앞에서 뒤로”또는 “뒤에서 앞으로” 복사하는 경우 겹치는 경우 memmove
에도 사용할 수 memcpy
있지만 memcpy
데이터 정렬 방법 및 / 또는 데이터 양에 따라 다른 방식으로 복사 할 수도 있습니다. 따라서 memcpy
시스템에서 복사 방법을 테스트하더라도 해당 테스트 결과가 항상 정확하다고 믿을 수는 없습니다.
어느 전화를 걸지 결정할 때 그것은 무엇을 의미합니까?
-
확실하게 알고
src
있고dst
겹치지 않는 한,memmove
항상 정확한 결과를 얻을 수 있고 일반적으로 필요한 복사 사례에 대해 가능한 한 빠르기 때문에 전화하십시오. -
확실히 알고
src
있고dst
겹치지memcpy
않으면 결과를 위해 어떤 것을 호출하든 상관 없으므로 전화하십시오.이 경우 둘 다 올바르게 작동하지만memmove
결코 더 빠르지 않으며memcpy
운이 좋지 않으면 천천히, 그래서 당신은 전화를 이길 수 있습니다memcpy
.
답변
하나는 중복 대상을 처리하고 다른 하나는 처리하지 않습니다.
답변
ISO / IEC : 9899 표준에서 간단하게 설명되어 있습니다.
7.21.2.1 memcpy 함수
[…]
2 memcpy 함수는 s2가 가리키는 객체에서 s1이 가리키는 객체로 n 개의 문자를 복사합니다. 겹치는 객체간에 복사가 발생하면 동작이 정의되지 않습니다.
과
7.21.2.2 memmove 기능
[…]
2 memmove 함수는 s2가 가리키는 개체에서 s1이 가리키는 개체로 n 개의 문자를 복사합니다. 복사는 s2가 가리키는 객체의 n 문자가 먼저 s1 및 s2가 가리키는 객체와 겹치지 않는 n 문자의 임시 배열에 복사 된 다음 임시 배열의 n 문자가 복사되는 것처럼 발생합니다. s1이 가리키는 객체.
질문에 따라 일반적으로 사용하는 것은 필요한 기능에 따라 다릅니다.
일반 텍스트에서 memcpy()
허용하지 않는 s1
및 s2
중복에, 잠시는 memmove()
않습니다.