|
: 질문 드렸던게 이런 내용입니다...
:
: typedef struct
: {
: int current_state;
: int event;
: int next_state;
: void (*funcptr)(int);
: }TABLE;
: 이런 구조체에서 함수 프로토타입 처럼 선언되어있죠...
: 실제 프로토타입은 아래와 같습니다... 많아서 중략했습니다...
:
: /* Function Prototypes */
: void sysinit(void);
: void play(int);
: void get_digits(int);
: void sethook(int);
: void wait_event();
: void check_event(int,int);
: void wtring(int);
: int process_event(int);
: int getxcord(int);
: int getycord(int);
: int getindex(HWND);
: int getindexvoice(HWND);
: :
: :
:
: 그리고 테이블구조체의 변수를 배열로 잡아 다음과 같이 초기화합니다...
:
: TABLE table[]=
: { /* current_state event next_stat function */
: { ST_WTRING, DE_RINGS, ST_OFFHOOK, setoffhk },
: { ST_OFFHOOK, DX_OFFHOOK, ST_PLAY, play },
: { ST_OFFHOOK, DE_LCOFF, ST_ONHOOK, sethook },
: { ST_PLAY, TM_EOD, ST_GETDIG, get_digits },
: { ST_PLAY, TM_MAXDTMF, ST_GETDIG, get_digits },
: { ST_PLAY, TM_LCOFF, ST_ONHOOK, sethook },
: { ST_GETDIG, TM_MAXDTMF, ST_CONFER, conference },
: { ST_GETDIG, TM_MAXTIME, ST_RING, ring },
: { ST_INVALID, TM_EOD, ST_GETDIG, get_digits },
: { ST_INVALID, TM_MAXDTMF, ST_GETDIG, get_digits },
: { ST_INVALID, TM_LCOFF, ST_ONHOOK, sethook },
: { ST_ROUTE, MSMM_ONHOOK, ST_ONHOOK, unroute },
: { ST_ROUTE, MSMM_HOOKFLASH,ST_INCONF, unroute },
: { ST_PLAYBUSY, TM_EOD, ST_ONHOOK, unroute },
: { ST_PLAYBUSY, TM_MAXDTMF, ST_ONHOOK, unroute },
: { ST_MSIROUTE, TDX_PLAYTONE, ST_INTXFRDIG, get_digits },
: { ST_MSIROUTE, MSMM_ONHOOK, ST_STOPCH, stopch },
: { ST_MSINVALID, TM_MAXDTMF, ST_INTXFRDIG, get_digits },
: { ST_MSINVALID, TM_EOD, ST_INTXFRDIG, get_digits },
: { ST_INTXFRDIG, MSMM_ONHOOK, ST_ONHOOK, stopch },
: { ST_CHKDIG, MSMM_ONHOOK, ST_ONHOOK, stopch },
: { ST_INTXFRDIG, TM_MAXTIME, ST_ONHOOK, unroute },
: { ST_MSINVALID, MSMM_ONHOOK, ST_ONHOOK, stopch },
: { ST_ONHOOK, TM_USRSTOP, ST_ONHOOK, unroute },
: { ST_INCONF, TDX_PLAYTONE, ST_INCONF, msunroute },
: { ST_PLAYBUSY, MSMM_ONHOOK, ST_ONHOOK, stopch },
: { ST_ONHOOK, DX_ONHOOK, ST_WTRING, wtring }
: :
: :
: :
: };
: 위에서처럼 마지막 인자에는 함수 이름만 적어넣었죠...
:
: LRESULT WINAPI ChildProcMsi(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
: {
: HDC hDC;
: PAINTSTRUCT ps;
: int i;
:
:
: switch(uMsg){
:
: case WM_CREATE:
: break;
:
: case WM_COMMAND:
:
: switch(LOWORD(wParam) ){
: case ADD_CONF: // have party added to conference
: i = getindex(hwnd);
: selection = MSPN_TS;
: dxinfo[msinfo[i].channel].state = ST_INCONF;
: (*unroute)(msinfo[i].channel);
: EnableWindow(hButtonAdd[i], FALSE);
: break;
:
: case ENTER_CONF:
: i = getindex(hwnd);
: dxinfo[msinfo[i].channel].state = ST_INCONF;
: selection = MSPN_STATION;
: (*stopch)(msinfo[i].channel);
: EnableWindow(hButtonEnter[i], FALSE);
: break;
: }
: break;
:
: :
: : 중략
: }
: 그리고 위에서 처럼 (*함수이름)(인자) 형태로 호출합니다...
: 임프님이 말씀하신 *(함수이름)(인자) 형태와 기능상으로는 같다고 봅니다...
: 아!! 똑같은거 아닌가요?? 괄호의 우선순위보다 '*'의 우선순위가 앞서기 때문에
: 인자가 들어가는 괄호'(' 보다 먼저 '*'가 인식이 먼저 되겠죠...
: 그래서 결국 함수 이름은 그 함수가 실행될 코드가 있는 포인터를 가르키니까
: 보통 쓰는 함수 호출방법과 함수이름 앞에 '*'를 붙여서 호출하나 기능은 똑같게 되겠죠???
: 맞나???(^^;)
: 근데 저렇게 쓰면 어떤 이점이 있는거죠??
: 모르겠당~~~~
: 그럼 안녕히...
:
:
:
임펠리테리입니다.
역시.. 함수의 포인터였군요. 처음부터 보셨던 소스를 같이 보여주셨으면 금방 답변드릴 수 있었을
텐데요. ^^
구조체 내에서, 다음과 같이 선언된 것이 바로 함수의 포인터입니다.
void (*funcptr)(int);
누군지, 포인터의 이름조차도 funcptr이라고 지었군요.
이 형태 이상 따로 설명드릴 것도 없습니다. 그 자체가 문법이랍니다. 좀 생소하게 보이시겠지만,
만약 함수의 포인터를 다음과 같이 선언하도록 문법을 만들었다면,
void *funcptr(int);
void * 형을 리턴하는 함수의 프로토타입과 구별이 안되니까요.
함수의 포인터란, 말 그대로 함수의 포인터입니다. 모든 포인터의 내부에 저장되는 값은 주소값
이란 것은 아시지요? 포인터의 형은 그 가리키는 값이 있는 곳에 있는 '것'이 무엇이냐를 결정하는
것입니다. 이 논리를 함수의 포인터로 적용해서 생각해보면, 함수의 포인터란, 역시 주소값을
가지고 있는데, 그 가리키는 곳에 있는 것이 함수의 시작 부분이라는 말이 됩니다.
그리고, 구조체의 선언 아래에 있는 table[] 배열을 봅시다. 구조체의 마지막 멤버가 함수의
포인터였듯이, 다른 함수들의 이름이 나열되어 있죠? 그래서.. 결국 다음과 같이 풀이됩니다.
void (*funcptr)(int); // 함수의 포인터 선언
funcptr = setoffhk; // 다른 함수의 주소로 함수포인터를 초기화
거꾸로 유추해보시면 아시겠지만, 함수이름 뒤에 () 없이 그냥 이름만 지정하면, 그 함수의 주소값
이 됩니다. 그래서 이런 대입연산이 가능한 것입니다.
결과적으로, funcptr 포인터는 setoffhk() 함수의 주소를 가지고 있게 되는 거죠.
모든 포인터는 다시 * 연산자를 앞에 붙이면 가리키는 주소에 있는 값이 된다는 거 아시죠?
그러므로 함수의 포인터도 앞에 *를 붙이면 가리키는 주소에 있는 함수를 호출할 수 있게 됩니다.
말씀하신 것처럼, (*함수이름)(인자) 의 형식으로 호출한다는 말입니다.
그래서, (*funcptr)(정수값) 라고 호출하면 setoffhk(정수값) 라고 호출한 것과 동일하게 됩니다.
그러면, 이런 함수의 포인터를 어디다가 써먹을까요?
호출할 함수의 타입, 즉 리턴값과 인자리스트는 확정되어있지만 여러 함수들 중 어떤 함수를
호출할 지 알수 없어서 경우에 따라 다른 함수를 호출해야 하거나, 혹은 DLL 내의 함수를 호출할
때처럼 코딩하고 있을 때는 호출할 함수가 아예 없는 경우에 쓰입니다. 특히 dll을 사용할 때는
함수의 포인터를 사용하지 않고는 dll 내부의 함수를 호출할 수 없습니다.
그럼 참고하시길...
|