Menu
Coddy logo textTech

제네릭 래퍼

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를 처리하는 방법에 대해 안전한 결정을 내릴 수 있게 합니다.

challenge icon

챌린지

쉬움

정수 또는 문자열 중 하나를 저장할 수 있는 type-safe Generic wrapper system을 만들어 보겠습니다. 어떤 타입을 보유하고 있는지 추적하여 나중에 data를 안전하게 검색하고 Print할 수 있도록 합니다.

코드를 세 개의 파일로 구성합니다:

  • wrapper.h: TYPE_INTTYPE_STRING 값을 갖는 DataType enum을 Define합니다. 그런 다음 void* data pointer와 DataType field를 하나로 묶는 Wrapper struct를 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합니다.

프로그램은 두 개의 입력을 받습니다:

  1. type indicator: integer의 경우 i, string의 경우 s
  2. wrap할 값

입력이 i42일 때의 예시 출력:

42

입력이 sHello일 때의 예시 출력:

Hello

입력이 i-100일 때의 예시 출력:

-100

입력이 sGeneric Programming일 때의 예시 출력:

Generic Programming

header file에서 include guards를 사용하는 것을 잊지 마세요. string copying을 위해 strlenstrcpy를 사용하여 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;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 C 컴파일러