함수 포인터나 복잡한 선언이 나올 경우 당황하지 않기 위해 쉽게 읽는 법에 대해 다루겠습니다.
일단 가장 먼저 다음 세 개 목록을 외우시기 바랍니다:
연산자 | 읽는 법 | 주의사항 |
* | 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 |