如何将地址转换为函数指针以调用方法

Posted

技术标签:

【中文标题】如何将地址转换为函数指针以调用方法【英文标题】:How to Convert Address to Function Pointer to Call Method 【发布时间】:2009-07-08 12:22:56 【问题描述】:

我想在 WaitAndCallFunc() 函数中调用 Test1() 方法。

代码:

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";

【问题讨论】:

【参考方案1】:

我不确定我理解你的问题到底是什么,但试试这个:

((func)pPtr)();

【讨论】:

【参考方案2】:

投射和调用:

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();

【讨论】:

这并不重要,因为这是澄清另一点,但您可能想在某个时候增加 i ;) 戴夫,快速令人印象深刻的答案:) 非常高兴。但是我得到了错误 C2064 的小错误:术语不计算为函数。我正在使用 VS 2005 VC++。请帮忙:) 谢谢 严格来说这是 C 的缩写形式。有一个更准确的版本,您可以传入 &Test1,我们调用 (*f)()。 他错误地将其转换为指向函数指针的指针。格雷格的回答是正确的。【参考方案3】:

严格来说,在 C 语言中,您不应该在函数指针和其他类型的指针之间进行转换。不能保证按您的预期工作。

所以一个更迂腐正确的版本看起来像这样:

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;

请注意,这里是与 void * 相互转换的结构指针,而不是函数指针本身。这还有一个好处是,如果您需要将更多值传递给 Test1(),您可以将更多值填充到结构中。

【讨论】:

+1 好技巧 :) 我喜欢它避免任何强制转换的方式 - 我想你也可以使用联合 union void* pv;无效 (*fp)(); 来回走呢?所有这些都是未定义的行为——所以我们可以做任何实际上最终在你的编译器上工作的事情——呵呵。 我很确定我的示例已全部定义——当然除了线程内容(来自 OP)!这带来了我应该提到的另一点——如果 OP 使用我展示的方法,他们将需要确保“hook_test1”对象的生存时间足够长,以便第二个线程使用它——这样做可能会更好全球性的,但这完全取决于平台的细节。【参考方案4】:

实际上,在当前的 C 或 C++ 中,直接不允许将函数指针转换为 void* 或将 void* 转换为函数指针 - 即使大多数编译器都会编译它。

在不编译直接转换的编译器上来回转换(使用 C 语法)有两种方法:

方法一(先转化为积分中介)

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

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

方法2(使用void**)

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

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

更多解释可以参考下面的帖子:Function pointers casting in C++

【讨论】:

我发现 GCC 会针对 *(void**) 行发出警告。一种让它安静的方法是先投到void*。这条线看起来像这样:*((void**)(void*)&amp;f) = pPtr;。当然,功能上是一样的…… 你不应该需要强制转换为 void* - C 和 C++ 都允许使用显式强制转换从任何一个对象指针转换为另一个 - 奇怪的是为什么 GCC 会在这里发出警告 - 因为显然你是无论如何都在未定义的领域。 它似乎警告取消引用。它记录了f 是一个函数指针,*(void**) 是一个void* 类型的左值:因此它给出了一个别名警告,这个类型双关语可能违反某些规则(3.10/15)。我怀疑,在两者之间转换为void* 使它“忘记”了对象的原始类型。当然,演员阵容在功能上没有任何改变(UB 保持 UB)。 如果你写:*((void**) &amp;Test1) 会发生什么 - 它仍然会发出警告吗? 是的,虽然这次没有访问任何值。这似乎是出于怀疑。它是这样做的:codepad.org/wbtFji75 :)

以上是关于如何将地址转换为函数指针以调用方法的主要内容,如果未能解决你的问题,请参考以下文章

将向量地址转换为本机指针是不是安全?

Python Cookbook(第3版)中文版:15.12 将函数指针转换为可调用对象

跳转某指定地址给某绝对地址赋值

易语言指针转换及调用方法

将c ++引用的地址传递给指针

如何使用 C++ lambda 将成员函数指针转换为普通函数指针以用作回调