CLangauge Complex Declaration
함수 포인터나 복잡한 선언이 나올 경우 당황하지 않기 위해 쉽게 읽는 법에 대해 다루겠습니다.
일단 가장 먼저 다음 세 개 목록을 외우시기 바랍니다:
복잡한 선언을 읽는 방법은 다음과 같습니다:
예를 들어 아래 선언을 읽어 봅시다:
int *a;
먼저 이름을 찾아야 합니다. 위 선언에서 "a"가 이름이니까, "a"부터 읽어나가면 됩니다.
a에서 가장 먼저 결합하는 기호는 "*"입니다. 따라서 위의 표를 참고로 하여 읽으면 다음과 같습니다:
a = a pointer to ...
그럼 이제 나머지는 "int"이므로 그냥 읽습니다:
a = a pointer to int
즉 "a"는 int를 가리키는 포인터 타입입니다.
좀 더 어려운 예를 들어봅시다.
int *(*foo)(int, int);
위 예에서 이름은 "foo"이므로, foo에서부터 읽어 나가면 됩니다. 가장 먼저 결합하는 것은 "foo"와 함께 괄호 안에 있는
"*"입니다. 차례대로 읽는 것을 표로 나타내면 다음과 같습니다 (현재 읽고 있는 부분은 @...@ 사이의 부분입니다):
즉 우리말로 읽자면, "foo"는 "int를 가리키는 포인터를 리턴하는 함수 (인자는 두 개의 int)를 가리키는 포인터"라 할 수 있습니다. 흔히 typedef를 써서 위와 같은 함수 포인터를 다른 이름으로 정의합니다:
typedef int (*proc_t)(const void *);
이 경우, "typedef"를 빼고 읽으면 됩니다. 즉,
물론 "typedef"를 썼으므로 이는 변수 선언이 아니라, 새로운 타입을 정의한 것이죠. 마지막으로 주의할 것은, 함수 인자에 이름이 있을 경우, 어떤 것이 기준이 되는 이름인지 잘 알고 읽어야 합니다. 예를 들어:
int (*proc_t)(int type, const void *data);
여기서 기준이 되는 이름은 "type", "data"가 아닌 "proc_t"입니다. 따라서 proc_t를 해석할 때에는 "type"이나 "data"에 신경쓸 필요는 없습니다.
TODO. 배열 N에 대한 예제를 만들 것.
TODO. 예제. "
int (*ap)[30]; ", "(*(void(*)())0)();", "void (*(*signal)(int, void (*)(int)))(int);"에 대한 설명을 넣을 것.
int (*ap)[30]
int *ap[30] (pointer arrays)
void (*(*signal)(int,void(*)(int)))(int);
cf. Chapter 5.12 Complicated Declaration from K&R 2nd Ed.
|
You can do very well in speculation where land or anything to do with earth is concerned. |