如何将地址转换为函数指针以调用方法
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*)&f) = pPtr;
。当然,功能上是一样的……
你不应该需要强制转换为 void* - C 和 C++ 都允许使用显式强制转换从任何一个对象指针转换为另一个 - 奇怪的是为什么 GCC 会在这里发出警告 - 因为显然你是无论如何都在未定义的领域。
它似乎警告取消引用。它记录了f
是一个函数指针,*(void**)
是一个void*
类型的左值:因此它给出了一个别名警告,这个类型双关语可能违反某些规则(3.10/15
)。我怀疑,在两者之间转换为void*
使它“忘记”了对象的原始类型。当然,演员阵容在功能上没有任何改变(UB 保持 UB)。
如果你写:*((void**) &Test1)
会发生什么 - 它仍然会发出警告吗?
是的,虽然这次没有访问任何值。这似乎是出于怀疑。它是这样做的:codepad.org/wbtFji75 :)以上是关于如何将地址转换为函数指针以调用方法的主要内容,如果未能解决你的问题,请参考以下文章