views:

703

answers:

4

Hi,

I wanted to call Test1() Method Within WaitAndCallFunc() Function.

Code:

typedef void (*func)();

void StartTimer(void* pFuncAddr);
void WaitAndCallFunc(void* pPtr);

void WaitAndCallFunc(void* pPtr)
{
    int i = 0;
    int nWaitTime = 3;

    while(1)
    {
     Sleep(1000);
    // I want pPtr to call Test1 Function;
     if(i == nWaitTime)
      break;
    }

    _endthread();
}
void StartTimer(void* pFuncAddr)
{
    _beginthread(WaitAndCallFunc, 0, pFuncAddr);
}
void Test1();
int main(int argc, char* argv[])
{

    StartTimer(Test1);

    Sleep(5000);

    return 0;
}

void Test1()
{
    cout << "Testing Thread\n";
}
+3  A: 

Cast and call:

typedef void (*func)();

void WaitAndCallFunc(void* pPtr)
{
    int i = 0;
    int nWaitTime = 3;

    while(1)
    {
        Sleep(1000);

        func f=(func)pPtr;   // cast to correct pointer to function type
        f();                 // and call!

        if(i == nWaitTime)
                break;
    }

    _endthread();
}
Dave Gamble
Not crucial since this is clarifying another point, but you probably want to increment i at some point ;)
Dave Gamble
Dave, Quick Impressive answer :) Very Happy. But small error i got error C2064: term does not evaluate to a function. I am using VS 2005 VC++. Please help :) Thanks
mahesh
Sorry... I just edited (take the *s out).
Dave Gamble
Dave Gamble
he's incorrectly cast it to a pointer to a function pointer. Greg's answer is correct.
Logan Capaldo
+3  A: 

I'm not sure I understand what your question is exactly, but try this:

((func)pPtr)();
Greg Hewgill
Greg,Awesome...Awesome...Awesome...Awesome.... Thanks soooo much
mahesh
+3  A: 

Strictly in C you're not supposed to convert between function pointers and other types of pointers. It's not guaranteed to work how you expect.

So a more pedantically correct version would look something like:

struct hook {
    void (*func)();
};

void StartTimer(void* pFuncAddr);
void WaitAndCallFunc(void* pPtr);

void WaitAndCallFunc(void* pPtr)
{
    struct hook *hook_ptr = pPtr;

    hook_ptr->func();

    _endthread();
}

void StartTimer(void* pFuncAddr)
{
    _beginthread(WaitAndCallFunc, 0, pFuncAddr);
}

void Test1();

int main(int argc, char* argv[])
{
    struct hook hook_test1 = { &Test1 };

    StartTimer(&hook_test1);

    Sleep(5000);

    return 0;
}

Note that in this it's the struct pointer that's cast to and from void *, not the function pointer itself. This also has the advantage that you can stuff some more values into the struct, if you need them to be passed down to Test1().

caf
+1 nice trick :) I like how it avoids any casting - I suppose you could use a union too union { void* pv; void (*fp)(); } to go back and forth too? All of this is undefined behavior - so we can do anything that actually ends up working on your compiler - heh.
Faisal Vali
I'm pretty sure my example is all defined - except for the thread stuff (from the OP) of course! That brings up another point I should mention - if the OP uses the method I've shown, they will need to ensure that the "hook_test1" object lives for long enough for the second thread to use it - it may be better to make it global, but that's all down to the particulars of the platform.
caf
+2  A: 

Actually, converting a function pointer to a void* or a void* to a function pointer is not directly allowed in current C or C++ - even though most compilers compile it.

There are two ways to convert back and forth (using C syntax) on compilers that don't compile the direct cast:

Method 1 (convert first to an integral intermediary)

((func) (intptr_t) pPtr)();  // call the void*

StartTimer( (void*) (intptr_t) &Test1); // pass function pointer to void*

Method 2 (use void**)

func f = 0;
*((void**)&f) = pPtr;
f();  

StartTimer( *((void**) &Test1)); // pass function pointer to void*

You can refer to the following thread for more of an explanation: http://stackoverflow.com/questions/1096341/function-pointers-casting-in-c/1096349#1096349

Faisal Vali
I find that GCC warns for the `*(void**)` line. A way to make it quiet is to cast to `void*` first. The line looks like this then: `*((void**)(void*)`. Of course, functionally this is the same...
Johannes Schaub - litb
You shouldn't need the cast to void* - both C and C++ allow the use of explicit casts to convert from any one object pointer to another - weird why GCC warns here - since clearly you're in undefined territory eitherway.
Faisal Vali
It seems to warn about the de-reference. It records that `f` is a function pointer, and `*(void**)` is an lvalue of type `void*`: It thus gives an aliasing warning that this type-pun may violate some rules (`3.10/15`). The cast to `void*` in between makes it "forget" about the original type of the object, i suspect. Of course the cast does not change anything functionally (UB stays UB).
Johannes Schaub - litb
Faisal Vali
Yeah, although there is no value accessed this time. It seems to do it on suspicion. Here is how it does: http://codepad.org/wbtFji75 :)
Johannes Schaub - litb
thanks for checking :)
Faisal Vali
Faisal,Nice Explanation :).
mahesh