function을 argument로 넘기기

theone3의 이미지

어제에 이어서 다른 질문 올라갑니다. 물론 어제의 문제도 해결한 것은 아닙니다만....

#include <iostream>
#include <pthread.h>

using namespace std;

typedef struct passing{
    int input;
    char in_string[128];
    int output;
} passing;


int thread_api(void *(*func)(void *));
void*  do_my_work(void * arg);

int main(int argc, char * argv[])
{
    passing main_pass;
    main_pass.input = 1111;
    sprintf(main_pass.in_string, "%s", "ABCDEF");


    if(thread_api(do_my_work(&main_pass)) != 0)
    {
        cout << "thread_api error" << endl;
    }


    cout << "output is " << main_pass.output;

    return(0);

}

void*  do_my_work(void * arg)
{
    passing * my_pass;
    my_pass = (passing *)arg;

    cout << "my_pass->input " << my_pass->input << endl;
    cout << "my_pass->in_string " << my_pass->in_string << endl;

    if(my_pass->input = 1111)
    {
        my_pass->output = 100;
    }

    cout << "do my work...." << endl;
    return(0);
}

int thread_api(void *(*func)(void * ))
{
    pthread_t   tid;
    int         status;
    int *       p_status = &status;
    int ret = 0;
    ret = pthread_create(&tid, 0, func, 0);
    if(ret != 0)
    {
        cout << "thread_create error" << endl;
        return(-1);
    }
    else
    {
        cout << "thread_create success" << endl;
    }

    ret = pthread_join(tid, (void **)&p_status);
    if(ret != 0)
    {
        cout << "thread_join error" << endl;
        return(-1);
    }
    else
    {
        cout << "thread_join success" << endl;
    }
    return(0);
}

Quote:

"th3.cpp", line 24: Error: Formal argument func of type void*(*)(void*) in call to thread_api(void*(*)(void*)) is being passed void*.

코드와 에러는 위와 같습니다.
제가 생각하기엔 같은 type으로 맞춰주었다고 생각하는데, 에러가 나는군요.
에러의 원인과 해결방안을 알려주시면 감사하겠습니다.

프로그램의 설명은 간단히 드리자면.
main에서 thread_api라는 함수를 호출하는데,
이 함수는 인자로 받은 함수를 pthread_create로 호출하고 끝냅니다.
do_my_work함수는 thread_api에 인자로 들어가는 예제 함수입니다.
passing structure는 do_my_work함수에 인자로 전달될 값과, 결과값을 가진 structure입니다.

Fe.head의 이미지

제 소견으로는

thread_api(do_my_work(&main_pass));

이 코드는
do_my_work 함수의 반환형이 void *이므로

thread_api(void *(0));

하고 같다고 생각합니다만.

thread_api(do_my_work);

이게 맞을것 같습니다.

고작 블로킹 하나, 고작 25점 중에 1점, 고작 부활동
"만약 그 순간이 온다면 그때가 네가 배구에 빠지는 순간이야"

theone3의 이미지

약간 다른 방식으로 구현을 했습니다.
고친 코드를 첨부합니다.

#include <iostream>
#include <pthread.h>

using namespace std;

typedef struct passing{
    int input;
    char in_string[128];
    int output;
} passing;


int thread_api(void *(*func)(void *), void * arg);
void*  do_my_work(void * arg);

int main(int argc, char * argv[])
{
    passing main_pass;
    main_pass.input = 1111;
    sprintf(main_pass.in_string, "%s", "ABCDEF");
   

    if(thread_api(do_my_work, &main_pass) != 0)
    {
        cout << "thread_api error" << endl;
    }

   
    cout << "output is " << main_pass.output;

    return(0);

}

void*  do_my_work(void * arg)
{
    passing * my_pass;
    my_pass = (passing *)arg;
   
    cout << "my_pass->input " << my_pass->input << endl;
    cout << "my_pass->in_string " << my_pass->in_string << endl;
   
    if(my_pass->input = 1111)
    {
        my_pass->output = 100;
    }
#include <iostream>
#include <pthread.h>

using namespace std;

typedef struct passing{
    int input;
    char in_string[128];
    int output;
} passing;


int thread_api(void *(*func)(void *), void * arg);
void*  do_my_work(void * arg);

int main(int argc, char * argv[])
{
    passing main_pass;
    main_pass.input = 1111;
    sprintf(main_pass.in_string, "%s", "ABCDEF");
   

    if(thread_api(do_my_work, &main_pass) != 0)
    {
        cout << "thread_api error" << endl;
    }

   
    cout << "output is " << main_pass.output;

    return(0);

}

void*  do_my_work(void * arg)
{
    passing * my_pass;
    my_pass = (passing *)arg;
   
    cout << "my_pass->input " << my_pass->input << endl;
    cout << "my_pass->in_string " << my_pass->in_string << endl;
   
    if(my_pass->input = 1111)
    {
        my_pass->output = 100;
    }

수정한 부분은 다음과 같습니다.

int thread_api(void *(*func)(void *), void * arg);


 if(thread_api(do_my_work, &main_pass) != 0)
    {
        cout << "thread_api error" << endl;
    }



int thread_api(void *(*func)(void * ), void * arg)


ret = pthread_create(&tid, 0, func, arg);

이렇게 하니 제가 원하는 대로 작동은 하는 것 같습니다만,
여기에 대해 명쾌하게 설명을 부탁드립니다.

당신은 사랑받기 위해 태어난 사람.

Fe.head의 이미지

int thread_api(void *(*func)(void *));
void*  do_my_work(void * arg);

int main(int argc, char * argv[])
{
    if(thread_api(do_my_work(&main_pass)) != 0)
    ...
}

void*  do_my_work(void * arg)
{
    ...
    return(0);
} 

위의 이전 코드에서

    if(thread_api(do_my_work(&main_pass)) != 0)

부분만 본다면

위의 code는 아래와 같이 2개로 나눌수 있습니다.

    void *p = do_my_work(&main_pass));
    if(thread_api(p) != 0)

이것은 dongyuri님이 원하시는 code가 아니시죠?

아래것을 원하셨을 겁니다.

   void * (p)(void *) = do_my_work;
    thread_api(p);

간단한 코드로 작성한다면

void foo(int *(p)())
{
   p();
}

int zero() 
{
     return 0;
}

int main()
{
    printf("%#x\n", zero());   /*  0이 출력 */
    foo(zero());                      /* foo(0); 호출 */

    printf("%#x\n", zero);      /*   zero의 주소가 출력 */
    foo(zero);                         /* foo(zero 의 주소); */
}

PS) 컴파일 안해 봤습니다.ㅡㅡ;

고작 블로킹 하나, 고작 25점 중에 1점, 고작 부활동
"만약 그 순간이 온다면 그때가 네가 배구에 빠지는 순간이야"

theone3의 이미지

Quote:

이것은 dongyuri님이 원하시는 code가 아니시죠?

아래것을 원하셨을 겁니다.

 

   void * (p)(void *) = do_my_work; 
    thread_api(p); 


제가 원한 것은 이렇습니다.


void * (*p)(void *) = do_my_work(&main_pass); 
    thread_api(p); 

p가 void *를 인자로 가지고, void *를 리턴하는 함수포인터로 생각했습니다.
따라서 당연히 인자(&main_pass)를 받아들일 수 있는 것으로 생각을 했습니다만, 제 생각대로 안 되더군요.
원래 안되는 것인지 궁금합니다.
설명 부탁드립니다. 아니면 참조할 문서라도 알려주시면 감사하겠습니다.

당신은 사랑받기 위해 태어난 사람.

chadr의 이미지

void * (*p)(void *) = do_my_work(&main_pass); 
    thread_api(p); 

void * (*p)(void *) = do_my_work(&main_pass); 는 함수호출하여 그 리턴 값을 저장하는 구문입니다.

질문자님께서 작성하신 함수 do_my_work는 void형 포인터를 리턴하게 되어있습니다. 이건 함수포인터와는 다릅니다.

void * != void * (*)(void *) 이며 컴파일러가 void * 와 void * (*)(void *)간의 형변환 방법을 모르기 때문에 이런 그렇습니다.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

theone3의 이미지

네. 답변 감사합니다. 잘 이해가 되는군요.

void * (*p)(void *) = do_my_work; 

위의 것은 함수 포인터의 할당이고요,

void * (*p)(void *) = do_my_work(&main_pass); 

이것은 do_my_work(&main_pass) 가 실행된 결과를 할당하는군요.
따라서 void *(*p)(void *)에 void *를 할당하려다 실패가 난 것이로군요.

답변 주신 모든 분들께 진심으로 감사드립니다.
오늘도 진전이 있는 하루입니다.

당신은 사랑받기 위해 태어난 사람.

익명 사용자의 이미지

간단히 말해서, 질문하신 분께서 함수 포인터에 대해 제대로 알고 있지 못하시군요. 가지고 계신 C언어 책의 함수 포인터 부분을 다시 한번 보시길 바랍니다.

void * (*p)(void *) = do_my_work(&main_pass);

위의 코드를 이해하기 쉽게 고치면 다음과 같습니다.

void * (*p)(void *);
p = do_my_work(&main_pass);

위 대입연산자의 양 변의 데이터형만 비교해도 왜 틀렸는지는 쉽게 나올것입니다. 왼쪽은 함수 포인터이고, 오른쪽은 do_my_work의 결과값인 void형 포인터입니다(함수 포인터와 void*형 포인터는 서로 호환되지 않습니다).

if(thread_api(do_my_work(&main_pass)) != 0)

"th3.cpp", line 24: Error: Formal argument func of type void*(*)(void*) in call to thread_api(void*(*)(void*)) is being passed void*.

위의 에러메시지는 매개변수로 함수 포인터가 와야할 곳에 void * 형 포인터가 왔기 때문에 발생한 것입니다.

해결 방법은 dongyuri 님께서 하신게 맞습니다. thread_api 함수에 함수 포인터와 매개변수를 따로 전달해 주어야 합니다.

참고로 pthread의 pthread_create 함수도 바로 그런 방식으로 처리를 합니다. 함수 포인터와 arg를 따로 받죠.

#include <pthread.h>
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void
*(*start_routine)(void *), void *arg);

쌀밥의 이미지

맨처음 코드에서

dongyuri wrote:
if(thread_api(do_my_work(&main_pass)) != 0)
{
cout << "thread_api error" << endl;
}

이부분은 잘못되었군요.

thread_api는 함수 포인터를 아규먼트로 받도록 되어있기 때문에
thread_api(do_my_work);
와 같이 사용하셔야 합니다.
보여주신 예에서는 thread_api(do_my_work(&main_pass));
와 같이 사용하셨는데
그러면 do_my_work(&main_pass)의 수형 결과인
(void *) 의 반환값을 thread_api라는 함수의 아규먼트로 사용하겠다는 것이 되기 때문에
문법 에러인것이죠...

일하는 사람들의 희망 민주노동당 : http://www.kdlp.org
반공 교육의 성과로, 민주주의의 반대가 공산주의(또는 사회주의)라고 생각하는 사람이 많다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.