Skip to content

61. 함수 포인터


1. 키워드

  • 함수 포인터


2. 함수 포인터 사용하기

  • C에서 함수는 이름이 정해져 있기 때문에 함수를 호출하려면 함수 이름으로 직접 호출했다.


void hello()
{
    printf("Hello, world!\n");
}

int main()
{
    hello(); // 함수 이름으로 함수를 직접 호출

    return 0;
}


  • C에는 함수를 배열 또는 구조체에 넣거나, 함수 자체를 함수의 매개변수로 넘겨주고, 반환값으로 가져올 수 있도록 함수 포인터라는 것을 만들어두었다.
  • 함수 포인터는 함수를 저장하는 포인터를 뜻하며 함수 포인터를 주고 받거나 함수 포인터로 함수를 호출할 수 있다.


001


  • 실제로 함수 이름도 포인터이므로 printf에서 출력해 보면 메모리 주소가 나온다.


void hello()
{
    printf("Hello, world!\n");
}

int main()
{
    printf("%p\n", hello); // 함수 이름도 포인터이므로 메모리 주소가 출력됨

    return 0;
}

// 0x00d1137f (메모리 주소. 컴퓨터마다, 실행할 때마다 달라짐)


3. 함수 포인터 만들기

  • 함수 포인터는 먼저 함수의 반환값 자료형을 지정해 주고, 함수 포인터 이름 앞에 *(애스터리스크)를 붙인 뒤 ()(괄호)로 묶어준다.
  • 그리고 다시 ()를 붙여 함수라는 것을 알려준다.


반환값자료형 (*함수포인터이름)();


  • 먼저 반환값과 매개변수가 없는 hello 함수가 있다.


void hello() // 반환값과 매개변수가 없음
{
    printf("Hello, world!\n");
}


  • 이 함수를 담을 수 있는 함수 포인터 fp(Function Pointer)는 다음과 같이 선언한다.


void (*fp)(); // 반환값과 매개변수가 없는 함수 포인터 fp 선언


  • 이제 함수 포인터를 사용해 보자.


#include <stdio.h>

void hello() // 반환값과 매개변수가 없음
{
    printf("Hello, world!\n");
}

void bonjour() // 반환값과 매개변수가 없음
{
    printf("bonjour le monde!\n");
}

int main()
{
    void (*fp)(); // 반환값과 매개변수가 없는 함수 포인터 fp 선언

    fp = hello; // hello 함수의 메모리 주소를 함수 포인터 fp에 저장
    fp();       // 함수 포인터로 hello 함수 호출

    fp = bonjour; // bonjour 함수의 메모리 주소를 함수 포인터 fp에 저장
    fp();         // 함수 포인터로 bonjour 함수 호출

    return 0;
}

// Hello, world!
// bonjour le monde!


  • 함수 포인터를 선언할 때는 함수 포인터와 저장될 함수의 반환값 자료형, 매개변수 자료형과 개수가 일치해야 한다.
  • 여기서는 반환값과 매개변수가 없는 hello, bonjour 함수를 저장할 것이므로 반환값은 void 타입으로 지정한다.
  • 그리고 (*fp)와 같이 함수 포인터 이름 fp 앞에 *를 붙이고 ()로 묶어준다.
  • 또한, 매개변수가 없으므로 ()만 붙이면 된다.


//↓ 반환값 자료형
void (*fp)(); // 반환값과 매개변수가 없는 함수 포인터 fp 정의
//     ↑   ↖ 매개변수가 없음
// 함수 포인터 이름


  • 함수의 메모리 주소를 함수 포인터에 저장할 때는 =(할당 연산자)에 함수 이름만 지정해 주면 된다.
  • 함수 이름 뒤에 ()를 붙이면 함수 호출이 되므로 주의한다.


fp = hello; // hello 함수의 메모리 주소를 함수 포인터 fp에 저장


  • 함수 포인터로 함수를 호출하는 방법은 간단하다.
  • 함수 포인터에 ()를 붙여서 호출하면 함수 포인터에 들어있는 함수가 호출된다.
  • 여기서 fp에 저장된 hello를 호출하므로 "Hello, world!"가 출력된다.


fp(); // 함수 포인터로 hello 함수 호출


  • fp에는 hello 함수 대신 bonjour 함수를 넣어서 호출해도 된다.
  • 즉, 함수 포인터를 사용하면 함수를 전구 소켓처럼 갈아 끼울 수 있다.


fp = bonjour; // bonjour 함수의 메모리 주소를 함수 포인터 fp에 저장
fp();         // 함수 포인터로 bonjour 함수 호출


4. 반환값과 매개변수가 있는 함수 포인터 만들기

  • 이번에는 반환값과 매개변수가 있는 함수 포인터를 만들어보자.
  • 다음과 같이 반환값 자료형을 지정해 주고, 맨 뒤의 ()에 매개변수의 자료형을 지정한다.
  • 이때 매개변수 이름은 생략해도 된다.


반환값자료형 (*함수포인터이름)(매개변수자료형1, 매개변수자료형2);


  • 예를 들어 int 타입 반환값, int 타입 매개변수가 두 개인 함수는 다음과 같다.


int add(int a, int b) // int 타입 반환값, int 타입 매개변수 두 개
{
    return a + b;
}


  • add 함수를 담을 수 있는 함수 포인터는 다음과 같이 만들 수 있다.


int (*fp)(int, int); // int 타입 반환값, int 타입 매개변수 두 개가 있는 함수 포인터 fp 선언


  • 이제 함수 포인터를 사용해 보자.


#include <stdio.h>

// 덧셈 함수
int add(int a, int b) // int 타입 반환값, int 타입 매개변수 두 개
{
    return a + b;
}

// 곱셈 함수
int mul(int a, int b) // int 타입 반환값, int 타입 매개변수 두 개
{
    return a * b;
}

int main()
{
    int (*fp)(int, int); // int 타입 반환값, int 타입 매개변수 두 개가 있는 함수 포인터 fp 선언

    fp = add;                   // add 함수의 메모리 주소를 함수 포인터 fp에 저장
    printf("%d\n", fp(10, 20)); // 함수 포인터로 add 함수를 호출하여 합을 구함

    fp = mul;                   // mul 함수의 메모리 주소를 함수 포인터 fp에 저장
    printf("%d\n", fp(10, 20)); // 함수 포인터로 mul 함수를 호출하여 곱을 구함

    return 0;
}

// 30
// 200


  • int 타입 반환값과 int 타입 매개변수 두 개를 가지고 있는 add, mul 함수를 저장할 것이므로 함수 포인터를 선언할 때 반환값은 int 타입으로 지정하고, 맨 뒤의 () 안에는 int 타입을 두 개 넣어준다.
  • 이때 매개변수의 자료형만 알려주면 되므로 매개변수의 이름은 지정하지 않아도 된다.


//↓ 반환값 자료형
int (*fp)(int, int); // int 타입 반환값, int 타입 매개변수 두 개가 있는 함수 포인터 fp 선언
//    ↑       ↖ int형 매개변수 두 개
// 함수 포인터 이름


  • 이제 =를 사용하여 함수 포인터에 add 함수의 메모리 주소를 저장한다.


fp = add; // add 함수의 메모리 주소를 함수 포인터 fp에 저장


  • 함수 포인터 fp()를 붙여서 호출하면서 매개변수에 값을 넣는다.
  • 여기서는 fp에 저장된 add 함수를 호출하므로 1020을 더한 값인 30이 나온다.


printf("%d\n", fp(10, 20)); // 함수 포인터로 add 함수를 호출하여 합을 구함


  • fpmul 함수를 넣어서 곱을 구할 수도 있다.


fp = mul;                   // mul 함수의 메모리 주소를 함수 포인터 fp에 저장
printf("%d\n", fp(10, 20)); // 함수 포인터로 mul 함수를 호출하여 합을 구함


  • 즉, 함수 포인터를 활용하면 상황에 따라서 함수를 바꿔가며 호출할 수 있다.


5. 함수 포인터 활용하기

  • 함수 포인터를 만드는 방법을 알아봤으니 이번에는 함수 포인터를 다양하게 활용해 보자.
  • 함수 포인터도 일반적인 포인터이므로 포인터로 할 수 있는 작업을 그대로 수행할 수 있다.
  • 함수 포인터를 배열로 만들기, 구조체 멤버로 사용하기, 함수의 매개변수와 반환값으로 사용하기 등이 가능하다.
  • 함수 포인터를 응용하면 함수를 고정된 형태가 아닌 데이터 형태로 취급할 수 있다.
  • 즉, 함수를 보관하거나 주고받기가 쉬워진다.


6. 함수 포인터 배열 사용하기

  • 먼저 사용자에게 함수 번호와 계산할 값을 입력받은 뒤 함수 포인터로 계산을 해보자.
  • 계산 함수는 int 타입 반환값, int 타입 매개변수 두 개를 가지고 있는 함수이며 0부터 3까지 번호를 매겼다.


int add(int a, int b):  0
int sub(int a, int b):  1
int mul(int a, int b):  2
int div(int a, int b):  3
#define _CRT_SECURE_NO_WARNINGS // scanf 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>

int add(int a, int b)
{
    return a + b;
}

int sub(int a, int b)
{
    return a - b;
}

int mul(int a, int b)
{
    return a * b;
}

int div(int a, int b)
{
    return a / b;
}

int main()
{
    int funcNumber; // 함수 번호
    int num1, num2;
    int (*fp)(int, int) = NULL; // int 타입 반환값, int 타입 매개변수 두 개가 있는 함수 포인터 선언

    printf("함수 번호와 계산할 값을 입력하세요: ");
    scanf("%d %d %d", &funcNumber, &num1, &num2); // 함수 번호와 계산할 값을 입력받음

    switch (funcNumber) // 함수 번호에 따라 함수 포인터 설정
    {
    case 0:       // 함수 번호에 따라 함수 포인터 설정
        fp = add; // 덧셈 함수
        break;
    case 1:       // 1이면
        fp = sub; // 뺄셈 함수
        break;
    case 2:       // 2이면
        fp = mul; // 곱셈 함수
        break;
    case 3:       // 3이면
        fp = div; // 나눗셈 함수
        break;
    }

    printf("%d\n", fp(num1, num2)); // 함수 포인터를 사용하여 계산 결과 출력

    return 0;
}

// 함수 번호와 계산할 값을 입력하세요: 0 10 20 (입력)
// 30


  • 함수 번호가 funcNumber에 저장된다.
  • switch 분기문에서 funcNumber에 따라 함수 포인터 fp에 함수의 주소를 넣어준다.
  • 여기서는 0을 입력했으므로 fpadd 함수가 들어간다.
  • 그리고 fp를 호출하여 1020을 더한 값인 30이 나왔다.


  • 함수를 번호로 나타내려고 하니 코드가 너무 길어진다.
  • 이때는 함수 포인터를 배열로 만들면 간단해진다.
  • 함수 포인터 배열은 함수 포인터를 선언할 때 함수 포인터 이름 뒤에 [](대괄호) 안에 배열의 크기를 지정하면 된다.


반환값자료형 (*함수포인터이름[크기])(매개변수자료형1, 매개변수자료형2);


  • 요소의 개수가 4개이며 add 함수를 담을 수 있는 함수 포인터 배열은 다음과 같이 만든다.


int (*fp[4])(int, int); // int 타입 반환값, int 타입 매개변수 두 개가 있는 함수 포인터 배열 선언


  • 이제 함수 포인터 배열을 사용해 보자.


#define _CRT_SECURE_NO_WARNINGS // scanf 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <string.h>

int add(int a, int b)
{
    return a + b;
}

int sub(int a, int b)
{
    return a - b;
}

int mul(int a, int b)
{
    return a * b;
}

int div(int a, int b)
{
    return a / b;
}

int main()
{
    int funcNumber; // 함수 번호
    int num1, num2;
    int (*fp[4])(int, int); // int 타입 반환값, int 타입 매개변수 두 개가 있는 함수 포인터 배열 선언

    fp[0] = add; // 첫 번째 요소에 덧셈 함수의 메모리 주소 저장
    fp[1] = sub; // 두 번째 요소에 뺄셈 함수의 메모리 주소 저장
    fp[2] = mul; // 세 번째 요소에 곱셈 함수의 메모리 주소 저장
    fp[3] = div; // 네 번째 요소에 나눗셈 함수의 메모리 주소 저장

    printf("함수 번호와 계산할 값을 입력하세요: ");
    scanf("%d %d %d", &funcNumber, &num1, &num2); // 함수 번호와 계산할 값을 입력받음

    printf("%d\n", fp[funcNumber](num1, num2)); // 함수 포인터 배열을 인덱스로 접근하여 함수 호출

    return 0;
}

// 함수 번호와 계산할 값을 입력하세요: 0 10 20 (입력)
// 30


  • 먼저 다음과 같이 함수 포인터 이름 fp 뒤에 []를 붙이고 크기를 4로 지정하여 요소가 4개인 함수 포인터 배열을 선언했다.


// int 타입 반환값, int 타입 매개변수 두 개가 있는 함수 포인터 배열 선언
//↓ 반환값 자료형
int (*fp[4])(int, int); // ← 매개변수 자료형
//    ↑   ↖ 크기가 4인 배열
// 함수 포인터 이름


  • 이제 fp는 배열이므로 인덱스로 접근할 수 있다.
  • 여기서는 add, sub, mul, div 함수의 메모리 주소를 각 요소에 저장했다.


fp[0] = add; // 첫 번째 요소에 덧셈 함수의 메모리 주소 저장
fp[1] = sub; // 두 번째 요소에 뺄셈 함수의 메모리 주소 저장
fp[2] = mul; // 세 번째 요소에 곱셈 함수의 메모리 주소 저장
fp[3] = div; // 네 번째 요소에 나눗셈 함수의 메모리 주소 저장


  • 함수 포인터 배열은 다음과 같이 인덱스를 사용하여 요소에 접근한 뒤 함수를 호출할 수 있다.
  • 따라서 fp[funcNumber](10, 20)과 같이 fp 뒤에 []를 붙이고 인덱스를 지정한 뒤 함수를 호출하면 된다.
  • 여기서는 0 10 20을 입력하여 funcNumber0이 들어있으므로 fp의 첫 번째 요소에 들어있는 add 함수가 호출된다.


printf("%d\n", fp[funcNumber](num1, num2)); // 함수 포인터 배열을 인덱스로 접근하여 함수 호출


  • 만약 배열에 들어있는 모든 함수를 호출하고 싶다면 반복문을 사용하면 된다.


// 배열의 요소 개수만큼 반복(요소 개수: 배열의 전체 크기 / 요소 한 개의 크기)
for (int i = 0; i < sizeof(fp) / sizeof(fp[0]); i++)
{
    printf("%d\n", fp[i](num1, num2)); // 함수 포인터 배열을 인덱스로 접근하여 함수 호출
}


  • 이처럼 함수 포인터 배열을 활용하면 함수 자체도 데이터화하여 함수 호출을 자동화할 수 있다.


함수 포인터 배열을 선언하는 동시에 초기화하기

  • 함수 포인터 배열도 {}(중괄호)를 사용하여 초기화할 수 있다.


int (*fp[4])(int, int) = { add, sub, mul, div }; // 중괄호로 함수의 메모리 주소를 저장


7. 함수 포인터를 구조체 멤버로 사용하기

  • 지금까지 구조체에는 일반 자료형으로 된 멤버를 넣었다.
  • 하지만 함수 포인터도 포인터이므로 구조체 멤버로 넣을 수 있다.
  • 함수 포인터를 구조체 멤버로 사용하려면 구조체를 정의할 때 멤버로 지정해 주면 된다.


struct 구조체이름 {
    반환값자료형 (*함수포인터이름)(매개변수자료형1, 매개변수자료형2);
};


  • 그럼 int 타입 반환값, int 타입 매개변수가 두 개인 함수를 구조체 멤버로 넣어보자.


int add(int a, int b) // int 타입 반환값, int 타입 매개변수 두 개
{
    return a + b;
}


  • add 함수를 담을 수 있는 구조체 멤버는 다음과 같이 만든다.


struct Calc {
//   ↓ 반환값 자료형
    int (*fp)(int, int); // 함수 포인터를 구조체 멤버로 지정
}; //     ↑       ↖ 매개변수 자료형
//    멤버 이름


  • 이제 구조체 멤버에 함수의 메모리 주소를 저장하고 사용해 보자.


#include <stdio.h>

struct Calc
{
    int (*fp)(int, int); // 함수 포인터를 구조체 멤버로 지정
};

int add(int a, int b) // int 타입 반환값, int 타입 매개변수 두 개
{
    return a + b;
}

int main()
{
    struct Calc c;

    c.fp = add; // add 함수의 메모리 주소를 구조체 c의 멤버에 저장

    printf("%d\n", c.fp(10, 20)); // 구조체 멤버로 add 함수 호출

    return 0;
}

// 30


  • 구조체를 정의할 때 멤버 부분에 함수 포인터를 만들어준다.
  • 여기서는 int 타입 반환값과 int 타입 매개변수 두 개를 가지고 있는 함수 포인터 fp를 넣었다.


struct Calc
{
    int (*fp)(int, int); // 함수 포인터를 구조체 멤버로 지정
};


  • 구조체 변수를 선언한 뒤 .(점)으로 함수 포인터 멤버에 접근하여 add 함수의 메모리 주소를 저장한다.
  • 만약 구조체 포인터에 메모리를 할당했다면 c->fp = add가 된다.


struct Calc c;

c.fp = add; // add 함수의 메모리 주소를 구조체 c의 멤버에 저장


  • 이제 구조체 멤버 fp()를 붙여서 함수를 호출할 수 있다.


변수.함수포인터(매개변수1, 매개변수2);


printf("%d\n", c.fp(10, 20)); // 구조체 멤버로 add 함수 호출


C와 객체지향

  • 보통 C는 객체지향 문법을 지원하지 않는다고 알려져 있다.
  • 하지만 C에서도 구조체와 함수 포인터를 활용하면 충분히 객체지향으로 프로그래밍을 할 수 있다.


struct block_device_operations
{
    int (*open)(struct block_device *, fmode_t);
    void (*release)(struct gendisk *, fmode_t);
    int (*rw_page)(struct block_device *, sector_t, struct page *, int rw);
    int (*ioctl)(struct block_device *, fmode_t, unsigned, unsigned long);
    int (*compat_ioctl)(struct block_device *, fmode_t, unsigned, unsigned long);
    long (*direct_access)(struct block_device *, sector_t,
                          void **, unsigned long *pfn, long size);
    unsigned int (*check_events)(struct gendisk *disk,
                                 unsigned int clearing);
    int (*media_changed)(struct gendisk *);
    void (*unlock_native_capacity)(struct gendisk *);
    int (*revalidate_disk)(struct gendisk *);
    int (*getgeo)(struct block_device *, struct hd_geometry *);
    void (*swap_slot_free_notify)(struct block_device *, unsigned long);
    struct module *owner;
};


8. 함수 포인터를 함수의 매개변수로 사용하기

  • 이번에는 함수 포인터를 매개변수와 함수의 반환값으로 사용해 보자.
  • 먼저 함수 포인터를 매개변수로 사용하려면 함수를 만들 때 매개변수 부분에 함수 포인터를 넣어주면 된다.


반환값자료형 함수이름(함수포인터반환값자료형 (*함수포인터이름)(함수포인터매개변수자료형1, 함수포인터매개변수자료형2))
{
}


  • add 함수를 매개변수로 전달하려면 함수를 다음과 같이 만든다.


void executor(int (*fp)(int, int))
{
}


  • 이제 함수를 완성하여 함수 포인터를 매개변수로 전달하고 사용해 보자.


#include <stdio.h>

int add(int a, int b) // int 타입 반환값, int 타입 매개변수 두 개
{
    return a + b;
}

void executor(int (*fp)(int, int)) // 함수 포인터를 매개변수로 지정
{
    printf("%d\n", fp(10, 20)); // 매개변수로 함수 호출
}

int main()
{
    executor(add); // executor를 호출할 때 add 함수의 메모리 주소를 전달

    return 0;
}

// 30


  • 함수를 정의할 때 매개변수 부분에 함수 포인터를 그대로 만들어주면 된다.
  • 따라서 함수 포인터 이름이 매개변수가 되므로 fp(10, 20)과 같이 매개변수로 함수를 호출하면 된다.


void executor(int (*fp)(int, int)) // 함수 포인터를 매개변수로 지정
{
    printf("%d\n", fp(10, 20)); // 매개변수로 함수 호출
}


  • 함수의 메모리 주소를 전달할 때는 함수 이름만 적어주면 된다.
  • add()처럼 ()까지 붙이면 add 함수가 호출되어 반환값이 executor에 전달되므로 주의한다.


executor(add); // executor를 호출할 때 add 함수의 메모리 주소를 전달


  • 다음과 같이 executor(add);를 풀어서 쓸 수도 있다.


int (*fp)(int, int);

fp = add;
executor(fp); // executor를 호출할 때 함수 포인터를 전달


9. 함수 포인터를 함수의 반환값으로 사용하기

  • 이번에는 함수 포인터를 반환값에 사용해 보자.
  • 반환값으로 사용할 때는 지금까지 사용했던 문법과는 조금 다르다.


함수포인터반환값자료형 (*함수이름(매개변수자료형 매개변수))(함수포인터매개변수자료형1, 함수포인터매개변수자료형2)
{
}


  • 함수에서 add 함수를 반환하려면 다음과 같이 만든다.


int (*getAdd())(int, int)
{
}


  • 이제 함수 안에서 함수 포인터를 반환하고, 바깥에서 사용해 보자.


#include <stdio.h>

int add(int a, int b) // int 타입 반환값, int 타입 매개변수 두 개
{
    return a + b;
}

int (*getAdd())(int, int) // 함수 포인터를 반환값으로 지정
{
    return add; // add 함수의 메모리 주소를 반환
}

int main()
{
    printf("%d\n", getAdd()(10, 20)); // getAdd를 호출한 뒤 반환값으로 add 함수 호출

    return 0;
}

// 30


  • 함수 포인터를 반환값으로 사용할 때는 먼저 (*getAdd())와 같이 * 뒤에 함수 이름을 지정하고 ()를 붙인다.
  • 다시 이 상태에서 ()로 묶어준 뒤 맨 앞에는 함수 포인터의 반환값 자료형, 맨 뒤 () 안에는 함수 포인터의 매개변수 자료형을 지정한다.
  • 함수 안에서는 return 키워드로 add 함수의 메모리 주소를 반환한다.


//↓ 함수 포인터의 반환값 자료형
int (*getAdd())(int, int) // 함수 포인터를 반환값으로 지정
{ //    ↑           ↑ 함수 포인터의 매개변수 자료형
  // 함수 이름
    return add; // add 함수의 메모리 주소를 반환
}


  • getAdd 함수를 호출하면 add 함수의 포인터가 반환된다.
  • 따라서 다음과 같이 getAdd 함수를 호출한 뒤 바로 ()를 붙여서 반환값으로 add 함수를 호출할 수 있다.


printf("%d\n", getAdd()(10, 20)); // getAdd를 호출한 뒤 반환값으로 add 함수 호출


  • 다음과 같이 getAdd()(10, 20)을 풀어서 쓸 수도 있다.


int (*fp)(int, int);

fp = getAdd(); // getAdd의 반환값을 함수 포인터 fp에 저장

printf("%d\n", fp(10, 20)); // 함수 포인터 fp로 add 함수 호출


매개변수가 있는 함수에서 함수 포인터 반환하기

  • 매개변수가 있는 함수에서 함수 포인터를 반환하려면 다음과 같이 getAdd 뒤의 () 안에 매개변수의 자료형과 매개변수 이름을 지정해 주면 된다.


int (*getAdd(int x, int y))(int, int) // 함수 포인터 반환, int 타입 매개변수 두 개
{
    printf("%d %d\n", x, y); // x, y는 getAdd 함수의 매개변수
    return add;
}

int main()
{
    printf("%d\n", getAdd(8, 9)(10, 20)); // 8, 9는 getAdd에 전달
                                          // 10, 20은 getAdd에서 반환된 add에 전달

    return 0;
}


10. typedef로 함수 포인터 별칭 정의하기

  • 지금까지 함수 포인터를 만들 때 int (*fp)(int, int);처럼 일일이 반환값 자료형과 매개변수 자료형을 명시해 주었다.
  • 이런 방식을 Full Pointer Type이라고 하는데 사용하기가 상당히 번거롭다.
  • 이때는 typedef로 별칭을 정의하면 함수 포인터를 매번 만들지 않아도 된다.


typedef 반환값자료형 (*함수포인터별칭)(매개변수자료형1, 매개변수자료형2);


  • 함수 포인터 별칭은 typedef 뒤에서 함수 포인터를 만들면 된다.


typedef int (*FP)(int, int);


  • 이제 함수 포인터 별칭을 사용해 보자.


#include <stdio.h>

int add(int a, int b) // int 타입 반환값, int 타입 매개변수 두 개
{
    return a + b;
}

typedef int (*FP)(int, int); // FP를 함수 포인터 별칭으로 정의

FP getAdd() // 함수 포인터 별칭을 반환값으로 지정
{
    return add; // add 함수의 메모리 주소를 반환
}

int main()
{
    printf("%d\n", getAdd()(10, 20)); // getAdd을 호출한 뒤 반환값으로 add 함수 호출

    return 0;
}

// 30


  • typedef가 앞에 붙는다는 점 말고는 일반적인 함수 포인터를 만드는 방법과 같다.


//       ↓ 반환값 자료형
typedef int (*FP)(int, int); // fp를 함수 포인터 별칭으로 정의
//            ↑       ↖ 매개변수 자료형
//     함수 포인터 별칭


  • 다음과 같이 함수 포인터 별칭을 함수의 반환값 자료형으로 지정할 수 있다.
  • getAdd의 모양이 훨씬 간단해졌다.


FP getAdd() // 함수 포인터 별칭을 반환값으로 지정
{
    return add; // add 함수의 메모리 주소를 반환
}


  • 물론 함수 포인터 별칭으로 포인터 변수(배열)를 선언하거나, 구조체 멤버 자료형, 함수의 매개변수 자료형으로도 사용할 수 있다.


#include <stdio.h>

int add(int a, int b) // int 타입 반환값, int 타입 매개변수 두 개
{
    return a + b;
}

typedef int (*FP)(int, int); // FP를 함수 포인터 별칭으로 정의

struct Calc
{
    FP fp; // 함수 포인터 별칭을 구조체 멤버 자료형으로 사용
};

void executor(FP fp) // 함수 포인터 별칭을 매개변수 자료형으로 사용
{
    printf("%d\n", fp(70, 80));
}

int main()
{
    FP fp1; // 함수 포인터 별칭으로 변수 선언
    fp1 = add;
    printf("%d\n", fp1(10, 20));

    FP fp[10]; // 함수 포인터 별칭으로 배열 선언
    fp[0] = add;
    printf("%d\n", fp[0](30, 40));

    struct Calc c;
    c.fp = add;
    printf("%d\n", c.fp(50, 60));

    executor(add); // executer를 호출할 때 add 함수의 메모리 주소를 전달

    return 0;
}

// 30
// 70
// 110
// 150

References