如何把C++成员函数的地址传给C
来源:互联网 发布:网络黄金egd未来城app 编辑:程序博客网 时间:2024/05/12 21:14
[CSDN][原创]
无意中试到一种把C++成员函数的地址传给C的方法,能骗过编译器,但是运行时堆栈错误,没太大实际意义,记在这里,权当消遣。
通常情况下C++的成员函数的地址是不能传给C的,除非是静态成员函数。因为普通成员函数有一个隐含的this指针,是C中没有的,如果和C之间互相调用,由于两边参数和堆栈的维护不兼容,会导致堆栈混乱出错。如果传递普通成员函数地址到C中,那么编译器会报错。
例如在C中有一个函数CFun01,需要一个回调函数指针作为参数:
// .cint CFunc01(int (*cb)(int)){return cb(0x55AA);}
在C++的类中定义一个函数并传给C:
// .cppclass C{public:int Fun01(int a){printf("C::Fun01: a = 0x%X\n", a);return 0;}int Fun02(int a){CFunc01(&C::Fun01);return 0;}};
在Fun02处编译器会报告错误:
error C2664: 'CFunc01' : cannot convert parameter 1 from 'int (__thiscall C::* )(int)' to 'int (__cdecl *)(int)'
There is no context in which this conversion is possible
通过下面的方法可以骗过编译器,强制将成员函数地址传给C:
// .cpp#include "stdarg.h"int GetFuncAddr(int t, ...){va_list va;va_start(va, t);int addr = va_arg(va, int);return addr;}extern "C" int CFunc01(int (*)(int));class C{public:int Fun01(int a){printf("C::Fun01: a = 0x%X\n", a);return 0;}int Fun02(int a){CFunc01((int (*)(int))GetFuncAddr(0, &C::Fun01));return 0;}};
在GetFuncAddr中,利用不定参数的特性,让编译器把函数地址放到堆栈上,然后从堆栈上再把函数地址用整数的形式取出来,这样就绕过了编译器的类型检查,很神奇的感觉。
以上方法在vs2005中测试通过,如果是VC6,把"&C::Fun01"换成"Fun01"即可。
不过虽然绕过了编译器,但是无法通过实际CPU运行,在实际运行中,C::Fun01可以被回调到,但该函数完成返回后堆栈就乱了。
运行结果:
C::Fun01: a = 0x55AA
运行结果是正确的,但运行后有错误提示:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
显然由于函数参数的压栈规则不一致,导致堆栈混乱了。
所以以上方法只能作为一种消遣,最终还是只能使用传统的静态成员的方法,无奈:
传统方法写在下面作为完结。
// .cint CFunc01(int (*cb)(void *, int), void *context){return cb(context, 0x55AA);}
// .cppextern "C" int CFunc01(int (*)(void *, int));class C{private:int Fun01(int a){printf("C::Fun01: a = 0x%X\n", a);return 0;}static int __Fun01(void *context, int a);public:int Fun02(int a){CFunc01(__Fun01);return 0;}};int C::__Fun01(void *context, int a){return ((C *)context)->Fun01(a);}int _tmain(int argc, _TCHAR* argv[]){C c;return c.Fun02(0);}
- 如何把C++成员函数的地址传给C
- 如何把vector和string数据传给旧的C API
- 【C/C++】类成员函数地址的获取及使用方法
- [c++]如何取重载函数的地址
- 把代码传给函数
- 获取成员方法的地址,将C++类成员方法转换成C自由函数
- 如何将c结构数据传给lua
- 如何将c结构数据传给lua
- C#&&Java-----C#中和Java中把主函数定义成静态成员函数的原因
- C++:类的成员函数
- 如何打印类成员函数的地址
- C++:如何声明和定义成员函数
- C/C++笔试系列--如何利用成员变量作为成员函数的默认参数
- c/c++笔试题——const类型的成员函数内部如何改变成员变量
- c/c++笔试题——const类型的成员函数内部如何改变成员变量
- 成员函数的地址
- c++const成员函数
- C++_const成员函数
- P2P技术(NAT基础)
- 智能指针总结
- Unity 3D The first project
- 关于绑定变量、关于占位符
- Hadoop 组成
- 如何把C++成员函数的地址传给C
- plot figure in R and store it.
- HDU 1565 黑白染色 最大点权独立集
- Java 中的 static 关键字
- 迅速榨干硬盘容量——由一次细节处理失误而引出的案例
- Hadoop 安装配置过程中出现问题总结
- 【驱动之四】Nt和Zw
- SRM 614
- POJ 3461 Oulipo(自己YY的模式匹配算法)