제네릭 스왑
Coddy C 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 51번째.
프로그래밍에서 흔한 작업 중 하나는 두 값을 서로 바꾸는 것입니다. 보통은 각 타입마다 별도의 swap 함수를 작성해야 합니다 — int를 위한 것, double을 위한 것 등과 같이 말이죠. 하지만 void*와 memcpy를 사용하면, 어떤 두 변수든 바꿀 수 있는 단일 함수를 작성할 수 있습니다.
핵심적인 통찰은 스와핑(swapping)이 단지 바이트를 이동시키는 것이라는 점입니다. 데이터의 크기를 알고 있다면, 실제 타입을 모르더라도 바이트를 복사할 수 있습니다. 함수 시그니처는 다음과 같습니다:
void generic_swap(void* a, void* b, size_t size);size 매개변수는 함수에게 이동할 바이트 수를 알려줍니다. 내부적으로는 임시 버퍼를 사용하고 <string.h>의 memcpy를 사용하여 바이트를 섞습니다:
void generic_swap(void* a, void* b, size_t size) {
char temp[size]; // temporary buffer
memcpy(temp, a, size); // temp = a
memcpy(a, b, size); // a = b
memcpy(b, temp, size); // b = temp
}이제 이 단일 함수는 모든 타입에 대해 작동합니다:
int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// 이제 x는 10, y는 5입니다double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p는 이제 2.71, q는 이제 3.14입니다이 패턴 — void*와 size_t를 사용하는 것 — 은 C 표준 라이브러리가 qsort 및 bsearch와 같은 제네릭 함수를 구현하는 방식입니다.
챌린지
쉬움void* 포인터와 memcpy의 강력한 기능을 사용하여 데이터 타입에 관계없이 두 변수의 값을 교환할 수 있는 제네릭 swap 유틸리티를 만들어 보겠습니다.
코드는 세 개의 파일로 구성됩니다:
swap.h: 두 개의void*포인터와 교환할 데이터의 크기를 나타내는size_t매개변수를 받는generic_swap함수를 선언하세요. 인클루드 가드(include guards)를 잊지 마세요!swap.c:generic_swap함수를 구현하세요. 임시 버퍼와memcpy를 사용하여 두 메모리 위치 간에 바이트를 이동합니다. 3단계 스왑 패턴을 기억하세요: 첫 번째 값을 임시 버퍼에 복사, 두 번째 값을 첫 번째 위치에 복사, 임시 버퍼의 값을 두 번째 위치에 복사.main.c: 다양한 데이터 타입에서 작동하는 제네릭 swap을 시연하세요. 타입 표시자(정수의 경우i, 실수의 경우d)와 두 개의 값을 읽습니다. 적절한 타입의 변수 두 개를 생성하고,generic_swap함수를 사용하여 값을 교환한 다음, 교환된 두 값을 출력합니다.
프로그램은 세 개의 입력을 받습니다:
- 타입 표시자: 정수의 경우
i또는 실수의 경우d - 첫 번째 값
- 두 번째 값
교환 후, 두 값을 각각 별도의 줄에 출력하세요. 실수의 경우 소수점 둘째 자리까지 출력합니다.
입력이 i, 5, 10일 때의 출력 예시:
10
5입력이 d, 3.14, 2.71일 때의 출력 예시:
2.71
3.14입력이 i, -7, 42일 때의 출력 예시:
42
-7입력이 d, 99.99, 0.01일 때의 출력 예시:
0.01
99.99이 방식의 장점은 generic_swap 함수가 어떤 타입을 교환하는지 알 필요 없이 단순히 바이트를 이동시킨다는 점입니다. 동일한 함수가 정수, 실수, 구조체 또는 기타 모든 데이터 타입에 대해 작동합니다. memcpy를 위해 <string.h>를, size_t를 위해 <stddef.h> 또는 <stdlib.h>를 포함해야 합니다.
치트 시트
제네릭 swap 함수는 실제 타입을 알지 못해도 바이트를 이동시켜 모든 타입의 값을 교환하기 위해 void* 포인터와 memcpy를 사용합니다.
함수 시그니처:
void generic_swap(void* a, void* b, size_t size);임시 버퍼와 memcpy를 사용한 구현:
void generic_swap(void* a, void* b, size_t size) {
char temp[size]; // 임시 버퍼
memcpy(temp, a, size); // temp = a
memcpy(a, b, size); // a = b
memcpy(b, temp, size); // b = temp
}다양한 타입에서의 사용 예시:
int x = 5, y = 10;
generic_swap(&x, &y, sizeof(int));
// x는 이제 10, y는 이제 5입니다
double p = 3.14, q = 2.71;
generic_swap(&p, &q, sizeof(double));
// p는 이제 2.71, q는 이제 3.14입니다필요한 헤더: memcpy를 위한 <string.h> 및 size_t를 위한 <stddef.h> 또는 <stdlib.h>.
직접 해보기
#include <stdio.h>
#include "swap.h"
int main() {
char type;
scanf("%c", &type);
if (type == 'i') {
int a, b;
scanf("%d", &a);
scanf("%d", &b);
// TODO: a와 b를 교환하기 위해 generic_swap을 호출하세요
// 힌트: &a, &b, 그리고 sizeof(int)를 사용하세요
printf("%d\n", a);
printf("%d\n", b);
} else if (type == 'd') {
double a, b;
scanf("%lf", &a);
scanf("%lf", &b);
// TODO: a와 b를 교환하기 위해 generic_swap을 호출하세요
// 힌트: &a, &b, 그리고 sizeof(double)를 사용하세요
printf("%.2f\n", a);
printf("%.2f\n", b);
}
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.