함수포인터에 대한 어려운 질문

익명 사용자의 이미지

#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번은 에러가 납니다.

방법을 좀 알고 계신 고수분이 있으면 한수 가르침을 부탁드
립니다.

익명 사용자의 이미지

굳이 인자로 넘기지 않겠다면
some real;
을 전역으로 두는 방법이 있겠지만,
이건 당연히 어처구니 없는 방법이겠죠.
결론적으로 말해서 인자로 넘기는 방법 이외에는 없습니다.

그리고 님이 작성하신 my_dir()처럼
my_dir()의 인자로 함수포인터와 그 함수의 인자를 함께 넘기는 방법은
라이브러리 작성시 아주 흔히 사용되는 일반화된 방법입니다.
그만큼 융통성이 좋다는 뜻이기도 하겠지만
다른 방법은 없다는 반증이기도 하겠지요? ^^

(여담 2번이 왜 에러가 나는지는 당연히 아시죠? ^^)

익명 사용자의 이미지

흐미~~~ 다른 방법이 없을 것 같기는 했는데...

정말 없네요..흑흑흑.

암튼 좋은 가르침 고마웠습니다.

담에도 또 그 담에도 좋은 가르침 부탁드리며....

정말 감사합니데이~~~ ^^;

익명 사용자의 이미지

지금의 버전은 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는 생각했었지만, 나머지 두가지는 고려해보지 못했
습니다)

히구..그나저나 능력이 될라나 모르겠네용~~~

하하..암튼 그럼 담에 또 뵙겠습니당.

다시한번 감사드리며...늘 건강하십시요.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.