검색결과 리스트
글
C에서는 선언문의 구조가 아주 복잡해지는 경우가 가끔 생긴다 간단한 경우에는 별 무제가 없지만 선언이 복잡해지면 뜻하지 않는 방법으로 선언이 되는 수도 있다. 선언은 외쪽에서 오른쪽으로 차례로 되는것이 아니므로 괄호를 많이 사용하게 되는 경우도 있다 다음의 두문장
int *f(); /* 정수형에 포인터를 리턴하는 함수 */
int (*pf)(); /* 정수를 리턴하는 함수의 포인터 */
를 생각해 보자 *는 앞에 붙는 연산자인데 괄호보다 우선순위가 낮기 때문에두번쨰 예에서는 괄호가 꼭 필요하다. 실제상황에서 아주 복잡하게 얽힌 선언문이 필요한 경우는 거의 없지만 이해할 필요가 있다 선언문을 작성하는 좋은 방법중 하나는 6.7에서 설명할 typedef를 사용하는 것이다 또 한가지 방법으로 여기서는 선언문을 말로 표현해주는 함수와 그 역동작을 하는 함수를 소개한다
우선 선언문을 설명으로 바꾸어 주는 함수 dcl에 대해 설명한다 실행 예를 몇가지 보이면 다음과 같다.
char **argv
argv: 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
dcl은 C의 선언에 관한 문법을 그대로 적용한 프로그램이다 구조는 다음과 같다
dcl: optional *'s direct-dcl
direct-dcl name
(dcl)
direct-dcl()
direct-dcl[optional size]
위에서 보듯이 direct-dcl을 선언 할떄 사용되는 이름등 직접적으로 선언하는데 사용되는 단어를 말하고 dcl은 그 단어앞에 *가 붙어서 포인터임을 나타내는것을 말한다 direct-dcl 뒤에()나[]가 붙은것도 direct-dcl이 된다 위의 설명을 잘 모르겠으면 다음의 예를 보자
(*pfa[])()
pfa는 이름이므로 direct-dcl이다 pfa[]도 direct-dcl이고 *pfa[]는 dcl로 인식된다. 그래서 (*pfa[])는 direct-dcl,(*pfa[])()는direct-dcl 이다
dcl 프로그램의 가장 중요한 부분은 dcl과 dirdcl이라 불리는 두 함수이다 이 두 프로그램은 되부름에 의해 반복적으로 불리면서 선언문을 분석해 낸다.
/* dcl: parse a declarator */
void dcl(void)
{
int ns;
for (ns = 0; gettoken() == '*'; ) /* count *'s */
ns++;
dirdcl();
while (ns-- > 0)
strcat(out, " pointer to");
}
/* dirdcl: parse a direct declarator */
void dirdcl(void)
{
int type;
if (tokentype == '(') { /* ( dcl ) */
dcl();
if (tokentype != ')')
printf("error: missing )\n");
} else if (tokentype == NAME) /* variable name */
strcpy(name, token);
else
printf("error: expected name or (dcl)\n");
while ((type=gettoken()) == PARENS || type == BRACKETS)
if (type == PARENS)
strcat(out, " function returning");
else {
strcat(out, " array");
strcat(out, token);
strcat(out, " of");
}
}
이 두 프로그램은 설명을 위해 만들어진 것 이기때문에 실제 사용하기에는 무리가 있다 데이터의 형도 문자형과 정수형밖에 다루지 못한다. 그러므로 함수 const 등을 처리하지 못한다 공백을 잘못쓰면 프로그램이 오작동하는 경우도 있다. 개선은 연습으로 남기고 우선 주 프로그램을 보인다
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXTOKEN 100
enum { NAME, PARENS, BRACKETS };
void dcl(void);
void dirdcl(void);
int gettoken(void);
int tokentype; /* type of last token */
char token[MAXTOKEN]; /* last token string */
char name[MAXTOKEN]; /* identifier name */
char datatype[MAXTOKEN];/* data type = char, int, etc. */
char out[1000]; /* output string */
int main() /* convert declaration to words */
{
while (gettoken() != EOF) { /* 1st token on line */
strcpy(datatype, token); /* is the datatype */
out[0] = '\0';
dcl(); /* parse rest of line */
if (tokentype != '\n')
printf("syntax error\n");
printf("%s: %s %s\n", name, out, datatype);
}
return 0;
}
gettoken 함수는 빈칸이나 탭은 무시하고 입력중에서 다음번 토큰을 찾는 함수이다. 토큰이라 함은 이름,숫자나 문자 한자가 들어있는 괄호나 대괄호등을 말한다.
int gettoken(void) /* return next token */ {
int c, getch(void);
void ungetch(int);
char *p = token;
while ((c = getch()) == ' ' || c == '\t')
;
if (c == '(') {
if ((c = getch()) == ')') {
strcpy(token, "()");
return tokentype = PARENS;
} else {
ungetch(c);
return tokentype = '(';
}
} else if (c == '[') {
for (*p++ = c; (*p++ = getch()) != ']'; )
;
*p = '\0';
return tokentype = BRACKETS;
} else if (isalpha(c)) {
for (*p++ = c; isalnum(c = getch()); )
*p++ = c;
*p = '\0';
ungetch(c);
return tokentype = NAME;
} else
return tokentype = c;
}
getch와 ungetch는 제 4장에서 설명했던 것이다.
말로 설명된 것을 선언문으로 바꾸는 것은 어렵지 않다 만약 x는 함수이고 리턴값은 문자를 리턴하는 함수들의 포인터 배열의 포인터라는 말을
x()*[]*() char
라고 표현하면
char (*(x())[])()
라고 표현해주는 함수 undcl을 생각한다. 말을 그대로 입력하지 않고 요약된 표현으로 된 입력을 사용하기 때문에 gettoken 함수를 사용할수 있다. undcl은 dcl과 같은 외부변수를 사용한다 프로그램은 다음과 같다.
예제 5-18 dcl의 입력에 에러가 있으면 고칠 수 있도록 해보라.
예제 5-19 undcl을 수정해서 결과로 나온 선언문에 필요 없는 괄호가 들어가지 않도록 하라.
예제 5-20 dcl을 보강해서 함수 매개변수나 그외 const등도 처리할 수있도록 만들어라.
'프로그래밍 > C' 카테고리의 다른 글
6.2 구조체와 함수(Structures and Functions) (0) | 2014.11.06 |
---|---|
6.1 구조체의 기본개념(Basics of Structures) (0) | 2014.11.06 |
5.11 함수의 포인터(Pointers to Functions) (0) | 2014.11.05 |
5.10 명령라인 매개변수(Command-line Arguments.) (0) | 2014.11.05 |
5.9 포인터와 다차원 배열(Pointers vs. Multi-dimensional Arrays) (0) | 2014.11.04 |
RECENT COMMENT