【问题标题】: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";
}

【问题讨论】:

    标签: c++ c multithreading function-pointers


    【解决方案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 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-24
      • 1970-01-01
      • 1970-01-01
      • 2021-10-31
      • 1970-01-01
      • 2017-04-04
      • 2018-12-10
      相关资源
      最近更新 更多