제네릭 래퍼
Coddy C 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 61개 중 50번째.
void*만으로도 모든 data를 저장할 수 있지만, 치명적인 결함이 있습니다. 어떤 type을 담고 있는지 추적할 수 없게 됩니다. 진정으로 유용한 Generic 컨테이너를 만들려면 data pointer를 type 정보와 결합해야 합니다. 바로 이때 Generic 래퍼 패턴이 사용됩니다.
아이디어는 간단합니다. void*를 저장된 타입을 식별하는 enum과 묶는 struct를 생성합니다. 이렇게 하면 wrapper는 항상 자신의 contents를 해석하는 방법을 알 수 있습니다.
typedef enum {
TYPE_INT,
TYPE_STRING
} DataType;
typedef struct {
void* data;
DataType type;
} Wrapper;data를 저장할 때는 실제 값에 대한 memory를 Allocate하고 해당 유형을 기록합니다. 검색할 때는 캐스팅하기 전에 유형을 Check합니다.
Wrapper wrap_int(int value) {
int* p = malloc(sizeof(int));
*p = value;
return (Wrapper){ .data = p, .type = TYPE_INT };
}
void print_wrapper(Wrapper* w) {
if (w->type == TYPE_INT) {
printf("%d\n", *(int*)w->data);
} else if (w->type == TYPE_STRING) {
printf("%s\n", (char*)w->data);
}
}이 패턴은 C에서 타입 안전한 Generic 컨테이너를 구축하기 위한 기반입니다. enum은 런타임 타입 태그로 작동하여, 코드가 저장된 data를 처리하는 방법에 대해 안전한 결정을 내릴 수 있게 합니다.
챌린지
쉬움정수 또는 문자열 중 하나를 저장할 수 있는 type-safe Generic wrapper system을 만들어 보겠습니다. 어떤 타입을 보유하고 있는지 추적하여 나중에 data를 안전하게 검색하고 Print할 수 있도록 합니다.
코드를 세 개의 파일로 구성합니다:
wrapper.h:TYPE_INT및TYPE_STRING값을 갖는DataTypeenum을 Define합니다. 그런 다음void*data pointer와DataTypefield를 하나로 묶는Wrapperstruct를 Define합니다. wrapper를 Create하고 contents를 Print하기 위한 Function prototypes를 Declare합니다.wrapper.c: wrapper Functionality를 Implement합니다:wrap_int: integer를 받아 memory를 Allocate하고 값을 Store한 다음, appropriately한 type tag가 포함된 Wrapper를 반환합니다wrap_string: string (char*)을 받아 memory를 Allocate하고 string을 복사한 다음, string type tag가 포함된 Wrapper를 반환합니다print_wrapper: type tag를 Check하고 data를 appropriately하게 Print합니다 (integer는 그대로, string은 그대로)free_wrapper: wrapper 내부에서 dynamically Allocate된 data를 Free합니다
main.c: 모든 요소를 하나로 결합합니다. type indicator(i는 integer,s는 string)를 값과 함께 읽습니다. appropriately한 wrapper를 Create하고 contents를 Print한 다음 memory를 Free합니다.
프로그램은 두 개의 입력을 받습니다:
- type indicator: integer의 경우
i, string의 경우s - wrap할 값
입력이 i와 42일 때의 예시 출력:
42입력이 s와 Hello일 때의 예시 출력:
Hello입력이 i와 -100일 때의 예시 출력:
-100입력이 s와 Generic Programming일 때의 예시 출력:
Generic Programmingheader file에서 include guards를 사용하는 것을 잊지 마세요. string copying을 위해 strlen과 strcpy를 사용하여 string과 null terminator를 위한 충분한 공간을 Allocate하세요.
직접 해보기
#include <stdio.h>
#include <string.h>
#include "wrapper.h"
int main() {
char type;
scanf("%c", &type);
getchar(); // 개행 문자 소비
Wrapper w;
if (type == 'i') {
int value;
scanf("%d", &value);
// TODO: wrap_int를 사용하여 정수 래퍼 생성
} else if (type == 's') {
char str[256];
fgets(str, sizeof(str), stdin);
// 후행 개행이 있으면 제거
str[strcspn(str, "\n")] = '\0';
// TODO: wrap_string을 사용하여 문자열 래퍼 생성
}
// TODO: print_wrapper를 사용하여 래퍼 내용 출력
// TODO: free_wrapper를 사용하여 래퍼 메모리 해제
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 C 컴파일러