어둠의 기술을 활용하여 C 에서 함수를 일급 객체처럼 쓰기

ms

mscjg

C 언어에서도 C++, Java 등과 같이 함수를 다른 함수의 인자로 넘겨줄 수 있습니다. 다만, 그 함수는 내부 상태를 가질 수 없다는 것이 한계이죠. 예를 들어, n을 인자로 주면 "항상 n을 리턴하는 함수"를 리턴하는 함수를 만들 수 없죠. 언어 명세 자체에 없는 기능입니다. 하지만 매크로를 이용하면 이걸 구현할 수 있지 않을까요?

#define FUNC_TYPE(type) __func_type_##type
#define FUNC_CAPTURE_TYPE(type) __func_capture_##type

#define DEFINE_FUNC_TYPE(type, return_type, capture_type, ...) \
    typedef capture_type FUNC_CAPTURE_TYPE(type); \
    typedef struct { \
        return_type (*func)(capture_type *capture, __VA_ARGS__); \
        capture_type capture; \
    } FUNC_TYPE(type); \
    return_type type(capture_type *capture, __VA_ARGS__)

#define CAPTURED(name) (capture->name)

#define FUNC_PASS(type, ...) (FUNC_TYPE(type)){ type, (FUNC_CAPTURE_TYPE(type)){ __VA_ARGS__ } }

#define FUNC_CALL(func_obj, ...) (func_obj.func(&func_obj.capture, __VA_ARGS__))

그래서 간단하게 만들어 봤습니다. 아래는 설명이 추가된 예제입니다.

//   캡처된 데이터를 저장하는 구조체
//           v
struct foo_capture {
    int cap1, cap2, cap3;
};

//                  앞서 정의한 구조체
//                 리턴값 타입 |                       파라메터
//        정의할 함수명   |    |                   ,------|-----,
                  v    v    v                   v      v     v
DEFINE_FUNC_TYPE(foo, int, struct foo_capture, arg1, arg2, arg3)
{
        CAPTURED() 매크로를 사용하여 캡처된 데이터에 접근
             v
    return CAPTURED(cap1) + CAPTURED(cap2) + CAPTURED(cap3) + arg1 + arg2 + arg3;
}

int func(FUNC_TYPE(foo) func, int arg1, int arg2, int arg3)
{
                      변수명
           함수 호출     |        파라메터
              |        |    ,-----|-----,
              v        |    v     v     v
    return FUNC_CALL(func, arg1, arg2, arg3);
}

int main(void)
{
                값 캡처 후 인자로 보내기
                        v
    int value = func(FUNC_PASS(foo, 1, 2, 3), 4, 5, 6);
    printf("%d = 21\n", value);
}

불러오는 중...