본문 바로가기

정보정보

함수 포인터 쓰는 법

C언어로 구현을 하다보면, CPP 의 확장성이 매우 아쉬울 때가 있는데,
함수포인터를 쓰면 나름   CPP 과 비슷하게? 확장적으로? 사용 가능하다.
이번 섹션(언제부터?ㅋ) 에서는 함수포인터를 잘 쓰는 법에 대해 공부해보고자 한다.
어차피 사용법을 알게 되면 사용 용도는 본인이 알아서 하는 것으므로 용도는 스킵.
 

ex)
 여러가지 미디어를 플레이 하고자 할때,
      video/image/sound 등의 미디어를 mime 타입별로 분류하여 통합함수리스트를 불러오고자 함.

각 mime type 별로 필요한 함수.
1. mime type valid 체크
2. 미디어 크기를 가지고 오는 함수
3. 미디어 플레이 start
4. 미디어 스톱
5. 미디어 off
6. 미디어 play time
7. free
...


-> 이런 경우, 함수구조체를 만들어서 각각의 함수를 구현한 다음에, mime type 별로 함수리스트를 긁어와서, 쓰면
   외부적으로는 interface 함수만 불러와서 사용가능함으로 맨위의 UI 단에서는 mimetype 별 함수가 아닌 통합interface 함수만 쓰면 되므로 매우 간단함.

사용법.
step 1.

필요한 함수를 생각해보고 함수 구조체 타입 선언
typedef struct
{
    const object_add_func_t add;
    const object_alloc_func_t alloc;
    const object_create_func_t create;
    const object_free_func_t free;
    const object_get_size_func_t get_size;
    const object_get_duration_func_t get_duration;
    const object_get_selection_func_t get_selection;
    const object_handle_signal_func_t handle_signal;
    const object_remove_func_t remove;
    const object_change_state_func_t pause;
    const object_change_state_func_t play;
    const object_change_state_func_t resume;
    const object_change_state_func_t rewind;
    const object_change_state_func_t stop;
} object_interface_t;

각각의 함수 타입은 필요한대로 만들어서 적당히 선언.
이런식으로

typedef void (*object_add_func_t)(void *obj_data,
    WindowHandle win, const Position *position);
typedef void (*object_free_func_t)(void *obj_data);

이 함수형 선언 및 함수 구조체 선언은 이 함수 구현부에서 가장 기본적인 부분이므로 소스구조에서 최대한 base가 되는 부분에 두도록 한다.)

step 2.
각각의 세부 함수를 만듬. 이런식으로 ㅋ
static const object_interface_t video_interface =   /*함수타입은 당연히 base 에서 선언한 object_interface_t를 써야됨*/
{
    object_video_add,
    object_video_alloc,
    object_video_create,
    NULL,
    object_video_delete,
    object_video_free,
    object_video_get_size,
    object_video_get_duration,
    object_video_remove,
    object_video_pause,
    object_video_play,
    object_video_resume,
    object_video_rewind,
    object_video_stop
};
static const object_interface_t sound_interface =
{
    object_sound_add,
    object_sound_alloc,
    object_sound_create,
    NULL,
    object_sound_delete,
    object_sound_free,
    object_sound_get_size,
    object_sound_get_duration,
    object_sound_remove,
    object_sound_pause,
    object_sound_play,
    object_sound_resume,
    object_sound_rewind,
    object_sound_stop
};
static const object_interface_t image_interface =
{
    object_image_add,
    object_image_alloc,
    object_image_create,
    NULL,
    object_image_delete,
    object_image_free,
    object_image_get_size,
    object_image_get_duration,
    object_image_remove,
    object_image_pause,
    object_image_play,
    object_image_resume,
    object_image_rewind,
    object_image_stop
};

-> 당연히 세부적인 항목은 mime type 별로 구현해 줘야 함.(함수 para/return 타입에 맞게 )


step 3.
이제 interface 함수를 구현해야함.
일단 연결은 이런식으로.
(처음부터 각각의 object 가 이 함수 list를 저장하고 있을 수도 있고, 아니면 interface 함수 실행시마다 찾아서 연결해줘도 됨.)

const object_interface_t* object_get_interface(const MSF_INT32 mime_type)
{
         if (mime_type == video)
        {
            return &video_interface; /*함수 list를 다 긁어옴*/
         }
        if (mime_type == mage)
        {
            return &image_interface;
        }
        if (mime_type == sound)
        {
            return &sound_interface;
        }
    return NULL;
}
interface 함수는 이런식으로 구현하면 된다.

void object_get_size(object_t *obj, MsfSize *size)
{
    MSF_ASSERT(NULL != obj);

    size->height = 0;
    size->width = 0;
   
    if (obj->plugin->get_size != NULL)
    {
        obj->plugin->get_size(obj->obj_data, size);
    }
}
void object_play(object_t *obj)
{
    ASSERT(NULL != obj);

    if (obj->plugin->play != NULL)
    {
        obj->plugin->play(obj->obj_data);
    }
}

이런식으로 함수의 UI에서는 mime type 에 따라 통합 함수를 쓰고, object_t의 plugin 구조체에 이 함수 list를 가지고 있어서 각각의 함수가 연결 가능함.
잠시 object_t의 구조를 보자면 요런식임
struct object_st{
    MSF_UINT32 object_id;
    void *obj_data;
    const object_interface_t *plugin;
    void *user_data;
};


 UI 단에서는 모든 mimetype 에 대해 object_play(object_t media) 를 쓰면 내부적으로는 미디어타입에 맞는
 함수 타입을 찾아 play까지 연결해주게 된다.

하하하