Menu
Coddy logo textTech

구조체 내의 함수 포인터

Coddy C 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 38번째.

지금까지 우리는 함수 포인터를 독립적인 변수로 사용하거나 인수로 전달해 왔습니다. 다형성을 향한 다음 단계는 함수 포인터를 구조체 내부에 직접 포함하여, 구조체에 고유한 동작(behavior)을 부여하는 것입니다.

구조체에 함수 포인터가 포함되어 있으면, 각 인스턴스는 서로 다른 함수를 가질 수 있습니다. 이는 같은 타입의 두 객체가 함수 포인터를 호출할 때 서로 다르게 동작할 수 있음을 의미합니다:

typedef void (*PrintFunc)(const char*);

typedef struct {
    const char* name;
    PrintFunc print;  // 멤버인 함수 포인터
} Printer;

Printer 구조체는 이제 두 개의 멤버를 가집니다: 데이터(name)와 동작(print). 이를 사용하려면, 초기화 중에 포인터에 함수를 할당합니다:

void loud_print(const char* msg) {
    printf("!!! %s !!!\n", msg);
}

int main() {
    Printer p;
    p.name = "Alert";
    p.print = loud_print;
    
    p.print("Hello");  // 출력: !!! Hello !!!
    return 0;
}

구조체를 통해 함수를 호출하는 방식에 주목하세요: p.print("Hello"). 이는 다른 언어에서 객체의 메서드를 호출하는 것과 매우 유사해 보입니다. 구조체는 데이터와 그 데이터를 처리하는 함수를 모두 가지고 있습니다.

이 패턴은 C 언어에서 다형성의 기초입니다. 서로 다른 인스턴스에 서로 다른 함수를 할당할 수 있어, 동일한 struct 타입에서 서로 다른 동작을 생성할 수 있습니다.

challenge icon

챌린지

쉬움

구조체가 함수 포인터를 통해 어떻게 자체적인 동작을 가질 수 있는지 보여주는 Notifier 시스템을 만들어 보겠습니다.

코드를 정리하기 위해 두 개의 파일을 생성합니다:

  • notifier.h: const char* 매개변수를 받고 아무것도 반환하지 않는 NotifyFunc라는 함수 포인터 타입을 정의합니다. 그런 다음 name (const char*)과 NotifyFunc 타입의 notify 함수 포인터를 포함하는 Notifier 구조체를 정의합니다.
  • main.c: 헤더 파일을 포함하고 다음 두 가지 알림 함수를 구현합니다:
    • alert_notify — 메시지를 [ALERT] message 형식으로 출력합니다.
    • info_notify — 메시지를 [INFO] message 형식으로 출력합니다.
    그 후 Notifier 인스턴스를 생성하고, 입력에 따라 적절한 함수를 연결한 다음, 구조체의 함수 포인터를 통해 알림을 호출합니다.

프로그램은 두 개의 입력을 받습니다: 알림 유형 (1은 alert, 2는 info)과 표시할 메시지입니다.

유형에 따라 해당 함수를 노티파이어의 notify 멤버에 할당한 다음, 구조체를 통해 함수를 호출하여 메시지를 표시하세요.

유형이 1이고 메시지가 "System starting"일 때의 출력 예시:

[ALERT] System starting

유형이 2이고 메시지가 "All systems normal"일 때의 출력 예시:

[INFO] All systems normal

헤더 파일에 include guard를 사용하는 것을 잊지 마세요. 그리고 구조체 멤버를 통해 함수를 호출하세요: n.notify(message)

치트 시트

함수 포인터는 구조체 내부에 직접 포함될 수 있으며, 각 인스턴스에 고유한 동작을 부여합니다. 이는 C 언어에서 다형성을 구현하는 기초가 됩니다.

함수 포인터를 포함한 구조체 정의하기

먼저 함수 포인터 타입을 정의한 다음, 이를 구조체 멤버로 포함시킵니다.

typedef void (*PrintFunc)(const char*);

typedef struct {
    const char* name;
    PrintFunc print;  // Function pointer as a member
} Printer;

구조체 사용하기

초기화 중에 포인터에 함수를 할당한 다음, 구조체를 통해 해당 함수를 호출합니다.

void loud_print(const char* msg) {
    printf("!!! %s !!!\n", msg);
}

int main() {
    Printer p;
    p.name = "Alert";
    p.print = loud_print;
    
    p.print("Hello");  // Output: !!! Hello !!!
    return 0;
}

p.print("Hello") 구문은 구조체를 통해 함수를 호출하며, 이는 다른 언어에서 객체의 메서드를 호출하는 것과 유사합니다.

다형성 동작

동일한 구조체 타입의 서로 다른 인스턴스에 서로 다른 함수를 할당할 수 있으므로, 동일한 구조체 타입에서 다양한 동작을 만들어낼 수 있습니다.

직접 해보기

#include <stdio.h>
#include "notifier.h"

// TODO: alert_notify 함수 구현하기
// 출력 형식: [ALERT] message


// TODO: info_notify 함수 구현하기
// 출력 형식: [INFO] message


int main() {
    int type;
    char message[256];
    
    // 입력 읽기
    scanf("%d", &type);
    getchar(); // 개행 문자 소비
    fgets(message, sizeof(message), stdin);
    
    // message 끝에 개행 문자가 있다면 제거
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: Notifier 인스턴스 생성
    
    
    // TODO: type에 따라 (1은 alert, 2는 info),
    // notifier의 notify 멤버에 적절한 함수 할당
    
    
    // TODO: 구조체의 함수 포인터를 통해 알림 호출
    // 사용법: n.notify(message)
    
    
    return 0;
}
quiz icon실력 점검

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

Object Oriented Programming의 모든 레슨