Memcpy 형변환 - Memcpy hyeongbyeonhwan

C언어, C++에서는 메모리를 조금 더 쉽게 다루고자하는 함수가 몇가지 존재합니다. 그것들이 무엇이 있는지 설명과 예제를 통해서 알아보도록 하겠습니다. 메모리 관련 함수를 사용하기 위해서는 string.h를 include해야합니다.

 

0) string.h 헤더파일 추가

메모리 관련 함수를 사용하기 위해서 반드시 추가해주세요.

 

1) void* memset(void* source, int value, size_t n)

메모리 주소 source부터 시작해 n만큼 value로 메모리를 채웁니다. return 값은 메모리의 시작주소입니다.

간단하네요. 그러면 예제를 바로 보도록 하겠습니다.

#include <stdio.h>
#include <string.h>

int main() {

	int nums1[5];
	unsigned char nums2[5];
	int i;

	memset(nums1, 10, sizeof(nums1));
	memset(nums2, 10, sizeof(nums2));
	
	for (i = 0; i < 5; i++) {
		printf("nums1[%d] = %d \n", i, nums1[i]);
	}
	
	printf("\n");

	for (i = 0; i < 5; i++) {
		printf("nums2[%d] = %d \n", i, nums2[i]);
	}
}

 

nums1과 nums2를 5개의 배열로 잡는데 자료형이 다르군요. nums1는 int형(여기서는 4바이트), nums2는 unsigned char형(1바이트)입니다. 이후 둘의 메모리를 memset으로 10으로 초기화합니다.

어떤 결과가 나올까요? 두개의 for문에서 nums1과 nums2의 요소들이 전부 10으로 나올것 같은데 그럴까요?

실행결과

nums1[0] = 168430090
nums1[1] = 168430090
nums1[2] = 168430090
nums1[3] = 168430090
nums1[4] = 168430090

nums2[0] = 10
nums2[1] = 10
nums2[2] = 10
nums2[3] = 10
nums2[4] = 10

 

우리의 예상과는 조금은 다릅니다. memset내부에서 실제 10이란 값은 unsigned char로 변환되어 1바이트의 메모리에 그 값을 집어넣게 되는겁니다. 

그래서 4바이트인 int형은 이런식으로 메모리가 set이 됩니다.

00001010 00001010 00001010 00001010 -> 168430090

Memcpy 형변환 - Memcpy hyeongbyeonhwan

memset은 1바이트 단위의 메모리를 세팅합니다. 그래서 unsigned char 형의 nums2는 제대로 된 값을 읽을 수 있습니다.

 

2) void* memcpy(void* destination, const void* source, size_t num)

이 함수는 source의 메모리를 destination으로 num만큼 복사합니다. 이 함수에는 source나 destination이 num바이트 이상인지를 검사하지 않으므로 상당히 취약하며 이진데이터를 그대로 복사합니다. 그러니 중간에 NULL이 있는지 없는지 확인하지 않습니다. 아래의 예제를 봅시다.

#include <stdio.h>
#include <string.h>

int main() {

	unsigned char source[8];
	int destination[2];
	int i;

	memset(source, 10, sizeof(source));

	memcpy(destination, source, sizeof(source));

	for (i = 0; i < 2; i++) {
		printf("destination[%d] : %d\n", i, destination[i]);
	}
}

 

source는 8바이트이고 destination도 8바이트입니다. 우선 source를 10으로 전부 채운 후에 destination으로 메모리 복사를 하면 어떤 결과가 나올까요?

 

이전의 memset에서 보았듯 바이트 단위로 메모리가 복사되어 8바이트가 0000 1010으로 복사되는 것이지요.

00001010 00001010 00001010 00001010 -> 168430090

따라서 168430090의 값이 두 번 출력되게 됩니다.

실행 결과

destination[0] : 168430090
destination[1] : 168430090

 

 

3) int memcmp(const void* ptr1, const void* ptr2, size_t num)

메모리의 바이트를 비교합니다. ptr1과 ptr2가 num만큼 비교했을 때 같다면 0, 아니면 다른 값을 리턴합니다. strcmp와 비슷한 리턴 값을 보이는데, unsigned char으로 ptr1이 ptr2보다 크다면 양수, 작다면 음수를 리턴하게 됩니다.

 

#include <stdio.h>
#include <string.h>

int main() {

	unsigned char a[5] = { 0,1,2,3,4 };
	unsigned char b[5] = { 0,1,2,3,4 };

	printf("memcmp(a,b) = %d \n", memcmp(a, b,5));
	
	a[0] = 100;
	
	printf("memcmp(a,b) = %d \n", memcmp(a, b, 5));

	b[0] = 200;

	printf("memcmp(a,b) = %d \n", memcmp(a, b, 5));
}

 

처음 a,b는 정확히 같은 값을 갖고 있으므로 비교했을때 0이 리턴됩니다.

이후 a의 0번째 요소가 100으로 a가 b보다 더 크므로 비교했을때 양수가 리턴됩니다. 

그 다음 b의 0번째 요소가 200으로 a가 b보다 더 작으므로 음수가 리턴되지요.

실행 결과

memcmp(a,b) = 0
memcmp(a,b) = 1
memcmp(a,b) = -1

 

4) void* memchr(void* ptr, int value, size_t num)

memchr은 ptr에서 value를 찾을때 사용합니다. 즉 메모리에서 특정 값을 찾을 때 사용하는 함수입니다. 만약 값이 존재한다면 그 주소를 리턴하고 아니면 NULL을 반환합니다.

 

#include <stdio.h>
#include <string.h>

void printMemory(void *ptr) {
	if (ptr == NULL) {
		printf("메모리에 존재하지 않음\n");
	}
	else {
		printf("메모리에 %d가 존재. addr : %p \n", *((unsigned char*)ptr),ptr);
	}
}
int main() {

	unsigned char arr[5] = { 0,1,2,3,4 };
	unsigned char a = 4;
	unsigned char b = 5;
	int i;

	for (i = 0; i < 5; i++) 
		printf("arr[%d] : %d, %p\n", i, arr[i], &arr[i]);
	
	
	void* ptr=memchr(arr, a, 5);
	printMemory(ptr);

	ptr = memchr(arr, b, 5);
	printMemory(ptr);
}

 

현재 1바이트 배열 arr에는 0,1,2,3,4가 있습니다. 여기에서 a(4)와 b(5)를 찾을 겁니다. a는 존재하니까 ptr이 NULL이 아닌 a가 존재하는 그 주소를 반환하겠지요. b는 존재하지 않으므로 NULL이 반환됩니다.