函数编译与执行及虚函数剖析(源码论证)

#pragma once
/*
   类 函数声明
*/
class Base;
class Base1;
class Base2;
class TestClass;


/*
  PFThisCall1 参数个数固定,则类stdcall方式编译 但是this指针则由ECX存放
  (int parm1)
*/
typedef void  (__stdcall *PFThisCall1)(int parm1);
/*
  PFThisCall2 参数个数不固定,则类cdecl方式编译 this指针会作为形参传递
  (TestClassFirst* pThis,int parmCount,int parm1,...)  
*/
typedef void  (__cdecl   *PFThisCall2)(TestClass* pThis,int parmCount,int parm1,...);
/*
  PFunc1代表一个参数的函数
 (TestClassFirst* pThis)
*/
typedef void  (__stdcall *PFunc1)(TestClass* pThis);
/*
  PFunc2代表两个参数的函数
 (TestClassFirst* pThis,int parm1)
*/
typedef void  (__stdcall *PFunc2)(TestClass* pThis,int parm1);
/*
  PFunc3代表三个参数的函数
 (TestClassFirst* pThis,int parm1,int parm2)
*/
typedef int   (__stdcall *PFunc3)(TestClass* pThis,int parm1,int parm2);


//类函数指针 原本就是__stdcall函数
typedef void  ( __stdcall TestClass::*PTestClassFunc1)();
typedef void  ( __stdcall TestClass::*PTestClassFunc2)(int parm1);
typedef int   ( __stdcall TestClass::*PTestClassFunc3)(int parm1,int parm2);


/*
这个数据结构主要是为了方便:
   类函数地址、普通函数地址与数值之间的转化
主要利用联合体共享内存的特征
*/
typedef unsigned long  Addr32;
typedef struct
{
unsigned long lAddr;
unsigned long hAddr;
}   Addr64;  


typedef union _FuncPtr
{
Addr64   addr64;  //64位地址
Addr32   addr32;  //32位地址

//普通函数指针
PFunc1    pFunc1;
PFunc2    pFunc2;
PFunc3    pFunc3;
//特殊指针
PFThisCall1 pFThisCall1;
PFThisCall2 pFThisCall2;
//类函数指针
PTestClassFunc1    pTestClassFunc1;
PTestClassFunc2    pTestClassFunc2;
PTestClassFunc3    pTestClassFunc3;
} FuncPtr;


/*
  GetClassMemberFuncAddr
  函数主要是为了根据任意函数地址转化为32位或64位的地址值
    memberFunc:任意一个函数(普通函数或者类的函数)
addr:一个32位或64位的保存函数地址值得变量
*/
template<typename ClassMemberFunc,typename MemberFuncAddr>
void GetClassMemberFuncAddr(ClassMemberFunc memberFunc,MemberFuncAddr &addr)
{
union{
ClassMemberFunc memberFunc;
MemberFuncAddr addr;
} converter;//定义共享内存变量


converter.memberFunc=memberFunc;
addr=converter.addr;
};


class Base
{
public:
Base();
~Base();


public:
virtual void __stdcall Func1();
};


class Base1: public Base
{
public:
Base1();
~Base1();


public:
virtual void __stdcall Func1();
virtual void __stdcall Func2(int param1);
};


class Base2: public Base
{
public:
Base2();
~Base2();


public:
virtual int  __stdcall Func3(int param1,int parm2);
};






class TestClass:public Base1,public Base2
{
public:
TestClass();
~TestClass();


private:
int m_intVal;


   /*
     thiscall声明的类函数 其this指针不一定是在函数形参中 得看函数参数个数
参数个数固定,则按stdcall方式编译
参数个数不固定,则按cdecl方式编译
   */
public:
//测试虚函数
//Base2 Func3重写
int  __stdcall Func3(int parm1,int parm2);
//TestClass
virtual void __stdcall Func4();
virtual void __stdcall Func5(int parm1);
virtual int  __stdcall Func6(int parm1,int parm2);




public:
//测试c++默认thiscall编译的函数
void  ThisCall1(int parm1); //参数固定   用stdcall编译 无this形参 ecx保存this
void  ThisCall2(int parmCount,...);//参数不固定 用cdecl编译   this指针是第一个形参



public:
void __stdcall Func7();
void __stdcall Func8(int parm1);
int  __stdcall Func9(int parm1,int parm2);




private:
void __stdcall PrivateFunc1();


};



#include "stdafx.h"
#include "TestClass.h"

Base::Base()
{


}

Base::~Base()
{


}
void Base::Func1()
{
long pointerValue=(long)this;
printf("Base::Func1 Run:\n this pointer=%x\n",pointerValue);
}
/
Base1::Base1()
{


}


Base1::~Base1()
{


}
void Base1::Func1()
{
long pointerValue=(long)this;
printf("Base1::Func1 Run:\n this pointer=%x\n",pointerValue);
}
void Base1::Func2(int parm1)
{
long pointerValue=(long)this;
printf("Base1::Func2 Run:\n this pointer=%x,parm1=%d\n",pointerValue,parm1);
}

Base2::Base2()
{


}


Base2::~Base2()
{


}
int Base2::Func3(int parm1,int parm2)
{
long pointerValue=(long)this;
printf("Base2::Func3 Run:\n this pointer=%x,parm1=%d,parm2=%d\n",pointerValue,parm1,parm2);
return parm1+parm2;
}

TestClass::TestClass()
{
m_intVal=0;
}


TestClass::~TestClass()
{


}


int TestClass::Func3(int parm1,int parm2)
{
long pointerValue=(long)this;
printf("Func3 Run:\n this pointer=%x,parm1=%d,parm2=%d\n",pointerValue,parm1,parm2);
return parm1;
}


void TestClass::Func4()
{
int temp=m_intVal;
m_intVal-=1;
long pointerValue=(long)this;
printf("Func4 Run:\n this pointer=%x,m_intVal=%d\n m_intVal-=1\n m_intVal=%d\n",pointerValue,temp,m_intVal);
}


void TestClass::Func5(int parm1)
{
int temp=m_intVal;
long pointerValue=(long)this;
m_intVal=parm1;
printf("Func5 Run:\n this pointer=%x,m_intVal=%d,parm1=%d\n m_intVal=parm1=%d\n",pointerValue,temp,parm1,m_intVal);
}


int TestClass::Func6(int parm1,int parm2)
{
int temp=m_intVal;
long pointerValue=(long)this;
m_intVal=parm1-parm2;
printf("Func6 Run:\n this pointer=%x,m_intVal=%d,parm1=%d,parm2=%d\n return value m_intVal=parm1-parm2=%d\n",pointerValue,temp,parm1,parm2,m_intVal);
return m_intVal;
}


void TestClass::Func7()
{
int temp=m_intVal;
    m_intVal+=1;
long pointerValue=(long)this;
printf("Func7 Run:\n this pointer=%x,m_intVal=%d\n m_intVal+=1\n m_intVal=%d\n",pointerValue,temp,m_intVal);
}


void TestClass::Func8(int parm1)
{
int temp=m_intVal;
long pointerValue=(long)this;
m_intVal-=parm1;
printf("Func8 Run:\n this pointer=%x,m_intVal=%d,parm1=%d\n m_intVal-=parm1\n m_intVal=%d\n",pointerValue,temp,parm1,m_intVal);
}

int  TestClass::Func9(int parm1,int parm2)
{
int temp=m_intVal;
long pointerValue=(long)this;
m_intVal=parm1+parm2;
printf("Func9 Run:\n this pointer=%x,m_intVal=%d,parm1=%d,parm2=%d\n return value m_intVal=parm1+parm2=%d\n",pointerValue,temp,parm1,parm2,m_intVal);
return m_intVal;
}


void TestClass::ThisCall1(int parm1)
{
int temp=m_intVal;
long pointerValue=(long)this;
m_intVal+=parm1;
printf("ThisCall1 Run:\n this pointer=%x,m_intVal=%d,parm1=%d\n m_intVal+=parm1\n m_intVal=%d\n",pointerValue,temp,parm1,m_intVal);
}


void TestClass::ThisCall2(int parmCount,...)
{
int temp=m_intVal;
va_list vaptr;
int i,j;
va_start(vaptr,parmCount);
for(i=0; i<parmCount;i++)
{
j= va_arg(vaptr,int);
m_intVal +=j;
}
va_end(vaptr);


long pointerValue=(long)this;
printf("ThisCall2 Run:\n this pointer=%x,m_intVal=%d,parmCount=%d,...\n m_intVal+=parm1+...\n m_intVal=%d\n",pointerValue,temp,parmCount,m_intVal);
}


void TestClass::PrivateFunc1()
{
long pointerValue=(long)this;
printf("PrivateFunc1 Run:\n this pointer=%x",pointerValue);
}

//执行文件

#include "stdafx.h"
#include "TestClass.h"


int _tmain(int argc, _TCHAR* argv[])
{
/*
 本程序主要功能:
    1.测试类函数获取
2.将获取的类函数执行
3.该方法对于虚函数会存在问题
*/


/*
 程序初始条件
*/
TestClass *pTestObj=new TestClass;//提供this指针对象
TestClass *pTestObjNew=new TestClass;//提供this指针对象
FuncPtr funcPtr;


/*
 (一)构造函数测试

      */




/*
(二)thiscall函数测试  
*/
/*
 ThisCall1函数参数个数一定 参照stdcall 但无this指针的形参 ecx保存this指针
*/
GetClassMemberFuncAddr(&TestClass::ThisCall1,funcPtr.addr32);
__asm
{
mov ecx, dword ptr [pTestObj]
}
funcPtr.pFThisCall1(-10);
/*
 ThisCall2函数参数个数不定 参照cdecl 但this指针是函数第一个形参
*/
GetClassMemberFuncAddr(&TestClass::ThisCall2,funcPtr.addr32);
funcPtr.pFThisCall2(pTestObj,3,9,50,62);
/*
(三)虚函数测试
主要验证虚函数表的获取
类对象的第一四字节 存放第一个父类和自身的所有虚函数地址存储空间(连续的一片小空间)的地址
        第二四字节 存放第二个父类所有虚函数地址存储空间(连续的一片小空间)的地址
所以类对象的首地址就相当于一个二维指针,包含了所有虚函数表,二每张表又包含了多个函数地址
(vfptr) Func1
          Func2
  Func4
  Func5
  Func6


(vfptr) Func1
  Func3
 
Func3函数不能正常运行 说明虚函数的地址 并不是靠函数名就能总是正确
*/
//Func1
GetClassMemberFuncAddr(&Base1::Func1,funcPtr.addr32);
funcPtr.pFunc1(pTestObj);//pTestObj传递this指针
//Func2
GetClassMemberFuncAddr(&TestClass::Func2,funcPtr.addr32);
funcPtr.pFunc2(pTestObj,678);//pTestObj传递this指针


//Func3此处 运行不正确 会运行Base1::Func2  总感觉跟虚函数的调用方式有关  不明白是怎么回事????
GetClassMemberFuncAddr(&TestClass::Func3,funcPtr.addr32);
funcPtr.pFunc3(pTestObj,-120,321);



Addr32 memObjAddr=(Addr32)pTestObj;//对象存放位置的前四个字节就是vfptr虚表指针
Addr32 **vfptr=(Addr32 **)(memObjAddr);
//虚函数表1执行
funcPtr.addr32=vfptr[0][0];//Base1 Func1
funcPtr.pFunc1(pTestObj);
funcPtr.addr32=vfptr[0][1];//Base1 Func2
funcPtr.pFunc2(pTestObj,12);
funcPtr.addr32=vfptr[0][2];//TestClass Func4
funcPtr.pFunc1(pTestObj);
funcPtr.addr32=vfptr[0][3];//TestClass Func5
funcPtr.pFunc2(pTestObj,21);
funcPtr.addr32=vfptr[0][4];//TestClass Func6
funcPtr.pFunc3(pTestObj,13,25);
//虚函数表2执行
funcPtr.addr32=vfptr[1][0];//Base Func1
funcPtr.pFunc1(pTestObj);
funcPtr.addr32=vfptr[1][1];//TestClass Func3
funcPtr.pFunc3(pTestObj,12,13);
/*
(四)类函数测试
*/
//Func7
GetClassMemberFuncAddr(&TestClass::Func7,funcPtr.addr32);
funcPtr.pFunc1(pTestObj);//pTestObj传递this指针
//Func8
GetClassMemberFuncAddr(&TestClass::Func8,funcPtr.addr32);
funcPtr.pFunc2(pTestObjNew,678);//pTestObj传递this指针
//Func9
GetClassMemberFuncAddr(&TestClass::Func9,funcPtr.addr32);
funcPtr.pFunc3(pTestObjNew,-120,321);//pTestObj传递this指针




delete pTestObj;
return 0;
}


附注:"stdafx.h"包含以下文件:

     #include <stdarg.h>

感悟:C++永远都是学不明白的语言 太复杂了 难学 难懂

问题:(1)红色注记部分运行原理还不明白 看看有没有谁能给我指点下????



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值