함수 포인터나 복잡한 선언이 나올 경우 당황하지 않기 위해 쉽게 읽는 법에 대해 다루겠습니다.

일단 가장 먼저 다음 세 개 목록을 외우시기 바랍니다:

연산자 읽는 법 주의사항
* a pointer to
(...) a function(...) returning 여기서 "..."는 인자 목록(parameter list)임
[N] array[N] of 여기서 N은 배열 크기를 나타냄

복잡한 선언을 읽는 방법은 다음과 같습니다:

  • 이름(identifier)이 있는 곳부터 차례대로 읽는다.
  • 읽는 순서는 연산자 결합 순위가 높은 것부터 읽는?

위 표에 나온 연산자는 "읽는 법"에 따라 읽되, 위 표의 괄호는 함수 선언을 위한 것입니다. 연산자 우선 순위를 변경하기 위한 괄호는 읽지 않습니다.

예를 들어 아래 선언을 읽어 봅시다:

int *a;

먼저 이름을 찾아야 합니다. 위 선언에서 "a"가 이름이니까, "a"부터 읽어나가면 됩니다. a에서 가장 먼저 결합하는 기호는 "*"입니다. 따라서 위의 표를 참고로 하여 읽으면 다음과 같습니다:

a = a pointer to ...

그럼 이제 나머지는 "int"이므로 그냥 읽습니다:

a = a pointer to int

즉 "a"는 int를 가리키는 포인터 타입입니다.

좀 더 어려운 예를 들어봅시다.

int *(*foo)(int, int);

위 예에서 이름은 "foo"이므로, foo에서부터 읽어 나가면 됩니다. 가장 먼저 결합하는 것은 "foo"와 함께 괄호 안에 있는 "*"입니다. 차례대로 읽는 것을 표로 나타내면 다음과 같습니다 (현재 읽고 있는 부분은 @...@ 사이의 부분입니다):

 int  * (@*foo@)(int, int) ; foo - a pointer to ...
 int  *@( *foo )(int, int)@; foo - a pointer to a function(int, int) returning ...
 int @* ( *foo )(int, int)@; foo - a pointer to a function(int, int) returning a pointer to ...
@int  * ( *foo )(int, int)@; foo - a pointer to a function(int, int) returning a pointer to int.

즉 우리말로 읽자면, "foo"는 "int를 가리키는 포인터를 리턴하는 함수 (인자는 두 개의 int)를 가리키는 포인터"라 할 수 있습니다.

흔히 typedef를 써서 위와 같은 함수 포인터를 다른 이름으로 정의합니다:

typedef int (*proc_t)(const void *);

이 경우, "typedef"를 빼고 읽으면 됩니다. 즉,

proc_t a pointer to function(const void *) returning int.

물론 "typedef"를 썼으므로 이는 변수 선언이 아니라, 새로운 타입을 정의한 것이죠.

마지막으로 주의할 것은, 함수 인자에 이름이 있을 경우, 어떤 것이 기준이 되는 이름인지 잘 알고 읽어야 합니다. 예를 들어:

int (*proc_t)(int type, const void *data);

여기서 기준이 되는 이름은 "type", "data"가 아닌 "proc_t"입니다. 따라서 proc_t를 해석할 때에는 "type"이나 "data"에 신경쓸 필요는 없습니다.

proc_t a pointer to function(int type, const void *data) returning int.



int (*ap)[30]
  int   (@*ap@)[30] ; ap - a pointer to ...
  int  @( *ap )[30]@; ap - a pointer to array[30] of
 @int   ( *ap )[30]@; ap - a pointer to array[30] of int

int *ap[30] (pointer arrays)
  int   *@ap[30]@ ; ap - an array[30] of ...
  int   @*ap[30]@ ; ap - an array[30] of a pointer to ...
  @int   *ap[30]@ ; ap - an array[30] of a pointer to int

void (*(*signal)(int,void(*)(int)))(int);
  void ( * (@*signal@)(int,void(*)(int)) )(int) ; signal - a pointer to ...
  void ( *@( *signal )(int,void(*)(int))@)(int) ; signal - a pointer to a function(int,void(*)(int)) returning ...
  void (@* ( *signal )(int,void(*)(int))@)(int) ; signal - a pointer to a function(int,void(*)(int)) returning a pointer to ...
  void@( * ( *signal )(int,void(*)(int)) )(int)@; signal - a pointer to a function(int,void(*)(int)) returning a pointer to a function(int) returning ...
 @void ( * ( *signal )(int,void(*)(int)) )(int)@; signal - a pointer to a function(int,void(*)(int)) returning a pointer to a function(int) returning void.

cf. Chapter 5.12 Complicated Declaration from K&R 2nd Ed.
  • int *f() /* f: function returning pointer to int */
  • int (*pf)() /* pf: pointer to function returning int */
  • char **argv /* argv: pointer to pointer to char */
  • int (*daytab)[13] /* daytab: pointer to array[13] of int */
  • int *daytab[13] /* daytab: array[13] of pointer to int */
  • void *comp() /* comp: function returning pointer to void */
  • void (*comp)() /* comp: pointer to function returning void */
  • char (*(*x())[])() /* x: function returning pointer to array[] of pointer to function returning char */
  • char (*(*x[3])())[5] /* x: array[3] of pointer to function returning pointer to array[5] of char */

'It's my study ^^ 과연' 카테고리의 다른 글

Love actually  (0) 2008.04.08
Big endian vs Little endian  (0) 2007.12.21
파일객체와 파일지시자 비교  (0) 2007.12.21
open, fopen의 차이점  (0) 2007.12.18
hard link와 symbolic link  (0) 2007.12.18

+ Recent posts