2010년 1월 29일 금요일

memcpy(), memmove()

하나의 배열은 다른 배열에 할당할 수 없으므로 하나의 배열을 한 요소씩 다른 배열에 복사하는 루프를 사용해 왔다. 문자 배열의 경우 한 가지 예외가 있다면  ctrcpy()와 strncpy() 함수를 이용해 왔다는 것이다 memcpy()와 memmove()함수는 다른 좀류의 배열에 대해서도 편리를 제공한다. 두함 수에 대한 원현은 다음과 같다.

void * memcpy(void *restrict s1, const void *restric s2, size_t n);
void * memmove(void *s1, const oid *s2, size_t n);

두 함수 모두 s2에 의해 포인트된 위치에서 s1에 포인트된 위치로 n바이트를 복사하여 s1값으로 봔환한다. 키워드 restrict(코드 최적화)로 나타나듯이, 이 두 함수의 다른 점은 memcpy()는 두개의 메모리 범위간의 중복이 없다고 가정할 수 있다는 것이다. memmove()함수는 그런 전제를 하지 않으므로 모든 바이트가 마지막 수신지에 복사되기 전에 임시 버퍼에 먼저 복사되는 것처럼 복사가 이루어진다. 만약 중복되는 범위가 있을때 memcpy()함수를 사용한다면 어떻게 될 것인가? 이 행위는 정의 되지 않는다. 즉, 실핼할 수도 있고 안 할 수도 있다는 뜻이다. 컴파일러는 memcpy()함수를 사용하지 말아야 할 때 사용하게 되면 그것을 멈출 수 없다. 따라서, 사용시 범위가 중복되지 않도록 확인하는 것은 사용자의 책임이다. 이것이 바로 프로그래머에게는 또하나의 부담이 될것이다.

이러한 함수들은 모든 데이터형과 작동하도록 설계되어 있기 때문에, 두개의 포인터 인수는 void형 포이터이다. C는 void *의 포인터에 어떤 포인터 형식도 할당할 수 있도록 해준다. 그러나 이 폭넓은 수용은 이러한 함수들이 어떤 종류의 데이터가 복사되는지 알지 못한다는 단점이 있다. 그러므로 이런 함수들은 복사될 바이트 수를 나타내기 위해 세 번째 인수를 사용한다. 일반적으로 배열의 경우, 바이트 수는 요소의 수가 아니라는 것을 주의한다. 따라서 10 double값의 배열을 복사했다면 세 번째 인수로 10이 아닌 10*sizeof(double)를  사용해야 할 것이다.


  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #define SIZE 10
  5
  6 void show_array(const int ar[], int n);
  7
  8 int main(void)
  9 {
 10    int values[SIZE] = {1,2,3,4,5,6,7,8,9,10};
 11    int target[SIZE];
 12    double curious[SIZE / 2] = {1.0, 2.0, 3.0, 4.0, 5.0};
 13    int * pi;
 14
 15    memcpy(target, values, SIZE * sizeof(int));
 16    puts("target:");
 17    show_array(target, SIZE);
 18    pi = (int *)malloc(SIZE * sizeof(int));
 19    memcpy(pi, values, SIZE * sizeof(int));
 20    puts("pi:");
 21    show_array(pi, SIZE);
 22    memmove(values + 2, values, 5);
 23    puts("values");
 24    show_array(values, SIZE);
 25    memcpy(target,curious, (SIZE /2) * sizeof(double));
 26    puts("target:");
 27    show_array(target, SIZE);
 28
 29    return 0;
 30 }
 31
 32 void show_array(const int ar[], int n)
 33 {
 34    int i;
 35    for(i = 0; i < n; i++)
 36       printf("%d ", ar[i]);
 37    putchar('\n');
 38 }
결과
target:
1 2 3 4 5 6 7 8 9 10
pi:
1 2 3 4 5 6 7 8 9 10
values
1 2 1 2 5 6 7 8 9 10
target:
0 1072693248 0 1073741824 0 1074266112 0 1074790400 0 1075052544

memcpy()에 대한 마지막 호출은 double형에서 int형 배열까지의 데이터를 복사한다. 이것은 memcpy()가 데이터형을 알지 모사며 그것에 대해 상관하지도 않는다는 것을 본여준다. 즉, 하나의 위치에서 다른 위치로 바이트를 복사할 뿐이다(예를들어, 구조체에서 문자 배열로 바이트를 복사할 수 있다.) 데이터 변환 또한 없다. 요소마다 지정하는 루프를 가지면 할당하는 동안 double형 값은 int형으로 변환될지도 모른다. 이경우에 프로그램은 바이트를 있는 그대로를 복사한 다음 그것이 int형인 것처럼 비트 패턴을 번역한다.














댓글 없음:

댓글 쓰기