함수포인터에 대한 어려운 질문
#include
#include
#include
#include
#include
#include
int func(char *, void *);
char * strrstr(char *, char *);
int my_dir(char *, int (*) (char *, void *), void *);
char * my_malloc(char * ptr, int * offset, int size);
typedef struct _a
{
char * content;
int offset;
} some;
main()
{
char *b = NULL;
some real;
real.content = NULL;
real.offset = 0;
printf("main func %x, \n", func);
if((b = getenv("Q_PATH")) == NULL)
{
return -1;
}
printf("main path is |%s|\n", b);
if ( my_dir ( b, func, (void *) &real) < 0) <== 1
/* if( my_dir (b, func(NULL, (void *) &real), (void *) &real)\
< 0) */ <== 2
puts("this is my_dir error\n");
printf("result is |%s|\n", real.content);
if( real.content != NULL)
free(real.content);
}
int my_dir(char * path, int (*func)(char *, void *), void *
something)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
int ret = 0;
if((dp = opendir(path)) == NULL)
{
printf("this is opendir error\n");
return -1;
}
chdir(path);
while((entry = readdir(dp)) != NULL)
{
lstat(entry->d_name, &statbuf);
if(S_ISREG(statbuf.st_mode))
{
if (strcmp(".", entry->d_name) == 0 ||
strcmp("..", entry->d_name) == 0)
continue;
3 ==> if ( (ret = func(entry->d_name, something)) < 0)
break;
continue;
}
}
closedir(dp);
return(ret);
}
int func(char *name, void * some1)
{
some * ptr = ( some * ) some1;
char temp[8 + 1];
char *t;
memset(temp, NULL, 8+1);
strcpy(temp, name);
if ((t = strrstr(temp, ".ctl")) == NULL )
{
printf("this is not fit pattern, name is |%s|\n", name);
return 0;
}
else
{
*t = '\0';
printf("==name is |%s|==\n", name);
printf("==need name is |%s|==\n", temp);
if ( ptr->content == NULL )
{
if( (ptr->content = my_malloc(ptr->content, &(ptr-
>offset),\
strlen(temp) + 2)) == NULL)
{
return -1;
}
} else
{
if( (ptr->content = my_malloc(ptr->content, &(ptr-
>offset),\
strlen(temp) + 1)) == NULL)
{
return -1;
}
}
strcat(ptr->content, temp);
strcat(ptr->content, "|");
printf("this is good pattern, name is |%s|\n", ptr->content);
return 0;
}
}
char * strrstr(char *target, char *sub)
{
char * t1;
char * t2;
t1 = target;
t2 = target;
while( t2 != NULL )
{
t1 = t2+1;
t2 = (char *)strstr(t1, sub);
}
if((t1-1) == target)
return NULL;
return t1-1;
}
char * my_malloc(char * ptr, int * offset, int size)
{
if((ptr = (void *)realloc(ptr, *offset + size)) == NULL)
{
printf("my_malloc error\n");
return NULL;
}
memset(ptr + *offset, NULL, size);
*offset += size;
return ptr;
}
------------------------------------------------------------
1. 설명
my_dir이란 함수를 이용하여 directory에서 어떤 형태의 일도
효과적으로 수행하기 위한 범용함수를 설계하였습니다.
my_dir의 선언에 나오는 func가 directory상에서 일을 할 수
있는 함수를 의미하며 그 인자로
첫째는 일을 처리할 파일이름 (char * name)
둘째는 그 일을 처리할 임의의 자료형 (void * some1)
이 있습니다.
실행하기 위하여 env에 Q_PATH가 있어야 하고 그 Q_PATH에
.ctl로 끝나는 다수의 파일이 존재해야 합니다.
2. 질문
이러한 일을 처리하기 위하여 함수를 설계하다가 보면, my_dir
을 호출하는 순간에 첫번째 인자로 들어갈 (char * name)에 대
한 정보는 모르지만 (void * some1)은 이미 그 주소를 알고 있
는 상태입니다.
하지만 my_dir의 인자로 주어지는 func가 함수포인터인 관계로
func에 주어질 (void * some1)의 인자는 단지 func에 인자로
주어지기 위하여 my_dir의 마지막 인자로 주어집니다.
만약, my_dir을 부르는 순간에 func에 (void * some1)의 주소
를 직접 전달할 다른 방법이 있다면 굳이 my_dir에 (void * so
me1)을 인자로 전달하지 않아도 될 터인데요....
(void * some1)를 my_dir에 전달한 후 func가 불려지는 순간에
다시 그 주소를 넘기는 방법이 아닌, my_dir을 호출하는 순간에
바로 func에 (void * some1)의 주소를 직접 전달하는 방법은 없
을까요?
즉 2번처럼 할 수 있으면 굳이 my_dir에 (void *some1)의 인자
를 만들지 않아도 될텐데요...참고로 2번은 에러가 납니다.
방법을 좀 알고 계신 고수분이 있으면 한수 가르침을 부탁드
립니다.
Re: 함수포인터에 대한 어려운 질문
굳이 인자로 넘기지 않겠다면
some real;
을 전역으로 두는 방법이 있겠지만,
이건 당연히 어처구니 없는 방법이겠죠.
결론적으로 말해서 인자로 넘기는 방법 이외에는 없습니다.
그리고 님이 작성하신 my_dir()처럼
my_dir()의 인자로 함수포인터와 그 함수의 인자를 함께 넘기는 방법은
라이브러리 작성시 아주 흔히 사용되는 일반화된 방법입니다.
그만큼 융통성이 좋다는 뜻이기도 하겠지만
다른 방법은 없다는 반증이기도 하겠지요? ^^
(여담 2번이 왜 에러가 나는지는 당연히 아시죠? ^^)
감사합니다...한수 배웠습니다.
흐미~~~ 다른 방법이 없을 것 같기는 했는데...
정말 없네요..흑흑흑.
암튼 좋은 가르침 고마웠습니다.
담에도 또 그 담에도 좋은 가르침 부탁드리며....
정말 감사합니데이~~~ ^^;
Re^3: 업그레이드 제안
지금의 버전은 2가지의 제약 사항이 있습니다.
1. regular file에 대해서만 작업을 할 수 있습니다.
2. 하위디렉토리까지 recursive하게 작업 할 수 없습니다.
int (*func)(char *name, void *arg);
를 이렇게 하면 어떨까요?
int (*func)(char *name, void *arg, mode_t type);
으로요...
my_dir()에서는 stat 구조체의 st_mode를 미리 검사하지 말고
func()의 type으로 무조건 넘기는 겁니다.
그리고 func()에서 판단을 해서 작업을 하는 거죠.
만일 recursive하게 하고 싶다면 func()를 이런 식으로 하면 될테고요.
int func(char *name, void *arg, mode_t type)
{
...
if(S_ISDIR(type))
my_dir(name, func, arg);
else if(S_ISREG(type))
하고 싶은 일;
...
}
이제 regular file에 대해서만 작업 할 수 있다는 점과
recursive는 안된다는 2가지 제약이 모두 해결되었네요...
어떠세요?
라이브러리 제작은 신중해야 합니다.
계속 손을 보게 되면 이미 그 라이브러리를 사용하던
다른 소스들도 그때마다 모두 바꿔야 하죠.
좋은 라이브러리 많이 만드셔서 공유하시죠 ^^
한가지만 더...
my_dir()에서 chdir()을 하는 것은 좋지 않습니다.
current working directory를 바꾸어서는 안되는 피치못할(^^) 사정이 있는
프로그램들은 사용할 수가 없습니다.
my_dir() 호출 후 main()에서 다시 원래 디렉토리로 chdir()을 하면 되지 않느냐
하실지도 모르겠지만, multi-thread에서는 어쩌시렵니까.
앞으로도 프로그램을 많이 짜시다 보면 그런 경우 꼭 나옵니다.
my_dir()에서 func()를 호출시 첫번째 인자를 entry->d_name으로 바로 하지 마시고
char name[1024];
sprintf(name, "%s/%s", path, entry->d_name);
으로 해서 path를 넘기는 방법으로 바꾸시는게 여러모로 좋습니다.
그렇게 해야 recrusive도 가능하죠.
후~~유... 길다... ^^
고맙다는 답변이 고마워 좀 더 떠들었네요 ^^
휴우~~~ 열심히 노력하겠습니다!!!
쩝...이런 팁까지...정말 고맙습니다.
힘 닿는데까지 노력해서 Upgrade Version을 만들어보도록 하죠.
(솔직히 recursive는 생각했었지만, 나머지 두가지는 고려해보지 못했
습니다)
히구..그나저나 능력이 될라나 모르겠네용~~~
하하..암튼 그럼 담에 또 뵙겠습니당.
다시한번 감사드리며...늘 건강하십시요.
댓글 달기