转载  获取成员函数的指针 收藏

 今天的话题比较有意思,如何获取一个非 static 成员函数的指针?考虑以下代码:

C++代码
  1. class A   
  2. {   
  3. public:   
  4.     void foo(void);   
  5. };   
  6.   
  7. void A::foo(void)   
  8. {   
  9.     puts("Hello, World!");   
  10. }  

也就是说,如何获取 A::foo 的指针?
那位说了:这有何难?一个 typedef 全搞定!

C++代码
  1. typedef void (A::*FooPtr)(void);   
  2. FooPtr func = &A::foo;  

且慢,我还没说完呢。我要把这个指针用于 thunk 技术,所以我希望得到一个 void* 类型的指针。这样一来,如果再使用一个类型转换的话,那么就会得到一个 C2440 的编译错误,因为 C++ 是强类型的,不允许我们胡作非为。
于是我们只能搞些歪门邪道了,且看:

方案一 汇编

C++代码
  1. void* func = NULL;   
  2. __asm   
  3. {   
  4.     push eax   
  5.     lea eax, A::foo   
  6.     mov func, eax   
  7.     pop eax   
  8. }  

优点:效率高,无废话。
缺点:可移植性差。

方案二 stdio

C++代码
  1. void* func = NULL;   
  2.   
  3. char addr[9];   
  4. sprintf(addr, "%p", &A::foo);   
  5. sscanf(addr, "%p", &func);  

优点:完全可移植。
缺点:效率低,而且有些无厘头。

从方案二中我们可以发现,sprintf 的可变参数可以绕过类型检查,于是我们得到了一个相对而言更优雅、开销更小的解决方案:

C++代码
  1. void* GetAddr(void* useless, ...)   
  2. {   
  3.     va_list arglist;    
  4.     void* ret;    
  5.   
  6.     va_start(arglist, useless);   
  7.     ret = va_arg(arglist, void*);    
  8.     va_end(arglist);   
  9.     return ret;   
  10. }   
  11.   
  12. void* func = GetAddr(NULL, &A::foo);  

另外需要指出的是,对于 VC 的 Debug 配置而言,以上的三种方式获取的都不是 A::foo 的真实地址,而是 ILT 的地址。因此如果我们需要的是真实地址的话,还需要另外解析 ILT 表项的代码。

目前为止最优雅的解决方案如下,由 likunkun 提供。

C++代码
  1. template <typename T>   
  2. inline void* pFun(T fun)   
  3. {   
  4.     return *(void **)&fun;   
  5. }   
  6. void *p = pFun(&A::foo);  

2009 年 2 月 1 日补记,利用 union 的解决方案:

C++代码
  1. union  
  2. {   
  3.     void (A::*pfoo)(void);   
  4.     void* p;   
  5. } u;   
  6.   
  7. u.pfoo = &A::foo;   
  8. void* func = u.p;  

转自:

http://www.titilima.cn/show-537-1.html

发表于 @ 2009年02月25日 15:22:00 | 评论( loading... ) | 编辑| 举报| 收藏

旧一篇:ODbgscript v1.50 release 中文说明

  • 发表评论
  • 评论内容:
  •  
Copyright © zhoujianhei
Powered by CSDN Blog