用汇编的眼光看c++(之模板函数)


【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】 


    如果说模板类定义的是一种数据类型,那么模板函数定义的就是一种函数。既然是函数,那么就有输入数据和输出数据。和模板类的概念差不多,模板函数的初衷也是为了在函数操作上抽取共同的特性,屏蔽的是类型的不同和差异。我们可以通过下面一个简单的代码说明问题:

int int_compare(int a, int b)
{
	return a > b ? a : b;
}

double double_compare(double a, double b)
{
	return a > b ? a : b;
}
    上面的一段代码是取较大值的一段代码。两个函数之间最大的差别就是输入数据类型和输出数据类型之间的差别,那我们有没有一种办法可以屏蔽这种数据类型之间的差别呢?有。那就是函数模板:

template <typename type>
type compare(type a, type b)
{
	return a > b ? a : b;
}
    可以看到,模板函数和普通函数没有什么区别,只是在函数的上面把类型抽象成了type,那么模板函数应该怎么使用呢?

246:      int i_value = compare(2, 3);
00401458   push        3
0040145A   push        2
0040145C   call        @ILT+10(compare) (0040100f)
00401461   add         esp,8
00401464   mov         dword ptr [ebp-4],eax
247:      double d_value = compare(2.3, 3.1);
00401467   push        4008CCCCh
0040146C   push        0CCCCCCCDh
00401471   push        40026666h
00401476   push        66666666h
0040147B   call        @ILT+5(compare) (0040100a)
00401480   add         esp,10h
00401483   fstp        qword ptr [ebp-0Ch]
248:  }
    汇编代码表明,两个compare调用的函数地址并不是一致的。其中整数的compare地址是0x40100f,而double的地址是0x0040100a。这说明编译器在编译的时候帮我们同时生成了两个compare函数。所以说,模板类的本质就是在编译器增加判断处理工作的同时,减少手工的重复劳动。同时和模板类不一样,模板函数不需要显示定义函数的参数类型,这是因为可以从入参判断出函数的类型。

    如果参数类型是 class类型呢? 我们可以试一试。首先定义基本class:

class data
{
	int value;
public:
	explicit data(int m): value(m) {}
	~data() {}
	int get_value() { return value;}
	int operator > (data& d) {return this->get_value() > d.get_value();}
};
    接着,我们调用compare函数:

256:      data m(4), n(2);
0040148D   push        4
0040148F   lea         ecx,[ebp-10h]
00401492   call        @ILT+40(data::data) (0040102d)
00401497   mov         dword ptr [ebp-4],0
0040149E   push        2
004014A0   lea         ecx,[ebp-14h]
004014A3   call        @ILT+40(data::data) (0040102d)
004014A8   mov         byte ptr [ebp-4],1
257:      data p = compare(m,n);
004014AC   mov         eax,dword ptr [ebp-14h]
004014AF   push        eax
004014B0   mov         ecx,dword ptr [ebp-10h]
004014B3   push        ecx
004014B4   lea         edx,[ebp-18h]
004014B7   push        edx
004014B8   call        @ILT+15(compare) (00401014)
004014BD   add         esp,0Ch
258:  }
    256行: data构造了两个基本变量m和n

    257行: 我们调用模板函数compare, 函数地址为0x401014,注意dx为p的地址,也就是堆栈临时变量的地址

    为了看到算术符>重载,我们跟进compare函数:

241:      return a > b ? a : b;
0040212B   lea         eax,[ebp+10h]
0040212E   push        eax
0040212F   lea         ecx,[ebp+0Ch]
00402132   call        @ILT+55(data::operator>) (0040103c)
00402137   test        eax,eax
00402139   je          compare+53h (00402143)
0040213B   lea         ecx,[ebp+0Ch]
0040213E   mov         dword ptr [ebp-18h],ecx
00402141   jmp         compare+59h (00402149)
00402143   lea         edx,[ebp+10h]
00402146   mov         dword ptr [ebp-18h],edx
00402149   mov         eax,dword ptr [ebp-18h]
0040214C   mov         dword ptr [ebp-10h],eax
0040214F   mov         ecx,dword ptr [ebp-10h]
00402152   mov         edx,dword ptr [ecx]
00402154   mov         eax,dword ptr [ebp+8]
00402157   mov         dword ptr [eax],edx
00402159   mov         ecx,dword ptr [ebp-14h]
0040215C   or          ecx,1
0040215F   mov         dword ptr [ebp-14h],ecx
00402162   mov         byte ptr [ebp-4],1
00402166   lea         ecx,[ebp+0Ch]
00402169   call        @ILT+25(data::~data) (0040101e)
0040216E   mov         byte ptr [ebp-4],0
00402172   lea         ecx,[ebp+10h]
00402175   call        @ILT+25(data::~data) (0040101e)
0040217A   mov         eax,dword ptr [ebp+8]
    我们发现compare模板语句下面构建了很多汇编语句,有一些冗长,我们可以大略介绍一下:

    (1)  开头调用call 0x0040103C函数就是调用重载运算符函数,[ebp-18h]表示即将被复制的是a数据还是b数据

    (2) 比较返回结果后,开始复制数据,具体见0x402157,其中临时变量[ebp-14h]和临时变量[ebp-4]的操作可以忽略

    (3) 函数返回前,对临时变量a和b进行析构处理,见代码0x402169和代码0x402175。


注意:

    (1)编写模板函数前先保证自己的函数是编写正确的

    (2)模板函数的优先级低于非模板函数

    (3)模板函数的类型可以是自定义类型,也可以是c、c++语言的基本类型

    (4)模板函数的使用经常和类的算术运算符混合使用,注意技巧

    (5)模板函数中涉及指针部分的内容,务必注意


【预告: 下一篇模板主要讲述特化模板、缺省模板】


  • 5
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式-老费

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值