2011년7월6일_함수를 인수받고 함수를 반환하는 괴상한 함수와 그 함수를 가리키는 함수포인터

 

평화로운 내장형class에 귀여운 학생들은 열심히 놀고 있다가…
흉폭한CM이 출현하여 하기와 같은 문제를 던져 주셨다. 잇힝

 

image


문제를 보고 순간 멍~해져서 어떻게 해야 할지 몰라 망설이고 있는데…
정환이가 나와서 두 번째 물음표에 들어갈 test( )의 인자를 적었다.

int (*p)(const char *,…)

왜 이렇게 들어가는지 한참 고민한 끝에 인자가 함수포인터라는 것을 알아내고,
나머지 ?칸을 채우기 위해 malloc( )의 원형을 찾아 보았다.


image

# man malloc

man page 보기 명령으로 malloc( )의 원형을 찾아 보니,
void *malloc(size_t);    이고, 함수이름을 (*)로 바꾸어 보면,
void *(*)(size_t);         가 된다.

여기까지 test( )에 적용하기 위해 (*)에서 *을 기준으로 좌측과 우측으로 분리하면,
void *(*       )(size_t);    이렇게 분리가 되고, *다음에 test함수명과 인자를 적자.
void *(*test(?))(size_t);    합체 후에 모습이 되고, ?안에 들어갈 type을 적기 위해 printf( )의 원형도 찾아보자.


image

# man 3 printf

printf( )는 linux명령으로도 있으니 3번 유저함수들을 보자.
int printf(const char *,…);   이고, 함수이름을 (*)로 바꾸면,
int (*)(const char *,…);       가 된다.

test( )를 호출하면서 인자로 printf( )의 주소를 건네주니 printf( )의 type과 일치하는 함수포인터를 선언해 인수받아야 한다.
함수포인터를 만들기 위해 (*)에서 *다음에 함수포인터명 p를 적어주면,
int (*p)(const char *,…)      가 된다.

두 가지, 반환type과 인자type을 적용하면,
void *(*test(int (*p)(const char *,…)))(size_t)            다했다!

test( )는 malloc의 주소를 반환한다.
malloc( )의 원형은,
void *malloc(size_t);    이고, 함수이름을 (*)로 바꾸어 보면,
void *(*)(size_t);         가 된다. (*)에서 *다음에 함수포인터명을 적어주면,
void *(*fp)(size_t);


<완성된 소스코드와 검증>

   1:  //함수를 인수받고 함수를 반환하는 괴상한 함수와 그 함수를 가리키는 함수포인터
   2:  #include <stdio.h>
   3:  #include <stdlib.h>
   4:   
   5:  void *(*test(int (*p)(const char *,...)))(size_t);
   6:   
   7:  int main()
   8:  {
   9:      int iNum = 0;
  10:      void *(*fp)(size_t) = 0;
  11:      //void *(*(*fp)(int (*)(const char *,...)))(size_t) = 0;
  12:      
  13:      fp = test(printf);
  14:      
  15:      printf("test()의 반환값\t\t\t \x1b[44m%08X\x1b[0m\n", fp);
  16:      printf("malloc()의 주소\t\t\t \x1b[44m%08X\x1b[0m\n", malloc);
  17:      printf("\nmain()의 주소\t\t\t \x1b[46m%08X\x1b[0m\n", main);
  18:      printf("비교대상 stack영역주소\t\t \x1b[46m%08X\x1b[0m\n", &iNum);
  19:      
  20:      return 0;
  21:  }
  22:   
  23:  void *(*test(int (*p)(const char *,...)))(size_t)
  24:  {
  25:      printf("인자로 받은 printf()의 주소\t \x1b[45m%08X\x1b[0m\n", p);
  26:      printf("printf()의 주소\t\t\t \x1b[45m%08X\x1b[0m\n\n", printf);
  27:      
  28:      return malloc;
  29:  }

 

<실행결과>

image

main( )에서 호출하며 printf( )의 시작주소를 test( )로 건네주고 함수포인터 p로 받는다.
그럼 p를 출력하면 printf( )의 주소가 나올 것이다.

printf(이름자체가 주소)와 p의 값을 출력하면 0x08048338로 똑같게 나온다.
컴파일시 경고메세지도 없고 출력결과도 같으니 type이 일치하고 잘 인수받은 것이 검증되었다.

test( )는 malloc( )의 시작주소를 반환한다. fp는 malloc( )의 원형과 type이 일치하여 test( )의 리턴값을 받는다.
그럼 이 둘을 출력하면 같은 주소가 나올 것이다.

test( )의 반환값인 fp와 malloc( )의 주소를 출력해보니 0x08048308로 같다.

상기의 출력된 값들만 보면 메모리의 어느 영역에 위치하고 있는지 알 수 없다.
그래서 비교대상으로 main( )의 주소와 stack영역의 지역변수 iNum의 주소를 출력해 보았다.
함수들은 모두 같은 영역에 위치한다는 것을 알 수 있고, 이렇게 함수들이 위치하는 영역을 Code영역이라고 한다.