제네릭 래퍼
Coddy C 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 61개 중 50번째.
void*만으로도 모든 데이터를 저장할 수 있지만, 치명적인 단점이 있습니다. 어떤 타입을 담고 있는지 추적할 수 없게 된다는 것입니다. 진정으로 유용한 제네릭 컨테이너를 만들려면 데이터 포인터를 타입 정보와 함께 사용해야 합니다. 여기서 제네릭 래퍼 패턴이 등장합니다.
아이디어는 간단합니다. void*와 저장된 유형을 식별하는 enum을 하나로 묶는 struct를 만듭니다. 이렇게 하면 wrapper는 언제나 해당 내용의 해석 방법을 알 수 있습니다.
typedef enum {
TYPE_INT,
TYPE_STRING
} DataType;
typedef struct {
void* data;
DataType type;
} Wrapper;데이터를 저장할 때는 실제 값을 위한 메모리를 할당하고 그 유형을 기록합니다. 데이터를 검색할 때는 캐스팅하기 전에 유형을 확인합니다.
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에서 타입 안전 제네릭 컨테이너를 구축하기 위한 기반입니다. enum은 런타임 타입 태그 역할을 하여, 코드가 저장된 데이터를 처리하는 방법에 대해 안전한 결정을 내릴 수 있도록 합니다.
챌린지
쉬움정수 또는 문자열을 저장할 수 있는 타입 안전 제네릭 래퍼 시스템을 만들어 보겠습니다. 래퍼가 어떤 타입을 보유하고 있는지 추적하여 나중에 데이터를 안전하게 가져오고 출력할 수 있도록 합니다.
코드를 세 개의 파일로 구성합니다:
wrapper.h:TYPE_INT및TYPE_STRING값을 갖는DataType열거형을 정의합니다. 그런 다음void*데이터 포인터와DataType필드를 묶는Wrapper구조체를 정의합니다. 래퍼를 생성하고 내용을 출력하기 위한 함수 프로토타입을 선언합니다.wrapper.c: 래퍼 기능을 구현합니다:wrap_int: 정수를 받아 메모리를 할당하고 값을 저장한 다음, 적절한 타입 태그가 지정된 Wrapper를 반환합니다wrap_string: 문자열(char*)을 받아 메모리를 할당하고 문자열을 복사한 다음, 문자열 타입 태그가 지정된 Wrapper를 반환합니다print_wrapper: 타입 태그를 확인하고 데이터를 적절한 방식으로 출력합니다(정수는 있는 그대로, 문자열은 있는 그대로).free_wrapper: 래퍼 내부에서 동적으로 할당된 데이터를 해제합니다
main.c: 모든 기능을 하나로 결합합니다. 값에 앞서 타입 표시자(i는 정수,s는 문자열)를 읽습니다. 적절한 래퍼를 생성하고, 내용을 출력한 다음 메모리를 해제합니다.
프로그램은 두 개의 입력을 받습니다:
- 타입 표시자: 정수는
i, 문자열은s - 래핑할 값
입력이 i와 42일 때의 예시 출력:
42입력이 s와 Hello일 때의 예시 출력:
Hello입력이 i와 -100일 때의 예시 출력:
-100입력이 s와 Generic Programming일 때의 예시 출력:
Generic Programming헤더 파일에서 인클루드 가드를 사용하는 것을 잊지 마세요. 문자열을 복사할 때는 strlen과 strcpy를 사용하여 문자열과 널 종결자를 저장할 수 있을 만큼 충분한 공간을 할당하세요.
직접 해보기
#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 컴파일러