从汇编角度看C++模板_C/C++_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > C/C++ > 从汇编角度看C++模板

从汇编角度看C++模板

 2016/5/12 5:33:18  jimmee  程序员俱乐部  我要评论(0)
  • 摘要:1.模板函数模板函数定义的就是一种函数。既然是函数,那么就有输入数据和输出数据。和模板类的概念差不多,模板函数的初衷也是为了在函数操作上抽取共同的特性,屏蔽的是类型的不同和差异。模板函数的反汇编示例:#include<stdio.h>#include<stdlib.h>template<typenametype>typecompare(typea,typeb){returna>b?a:b;};intmain(void){intv=compare(2,3
  • 标签:模板 汇编 c++
  • 1. 模板函数 ????????

??????? 模板函数定义的就是一种函数。既然是函数,那么就有输入数据和输出数据。和模板类的概念差不多,模板函数的初衷也是为了在函数操作上抽取共同的特性,屏蔽的是类型的不同和差异。

??????? 模板函数的反汇编示例:

????

class="cpp">#include <stdio.h>
#include <stdlib.h>

template <typename type>
type compare(type a, type b)
{
    return a > b ? a : b;
};

int main(void) {
	int v = compare(2, 3);
	double v2 = compare(2.5, 3.5);
	printf("v=%d,v2=%f", v, v2);
}

?

?

?????

           main():
080483e4:   push %ebp
080483e5:   mov %esp,%ebp
080483e7:   and $0xfffffff0,%esp
080483ea:   sub $0x20,%esp
11        	int v = compare(2, 3);
080483ed:   movl $0x3,0x4(%esp)
080483f5:   movl $0x2,(%esp)
080483fc:   call 0x8048444 <compare<int>(int, int)>
08048401:   mov %eax,0x1c(%esp)
12        	double v2 = compare(2.5, 3.5);
08048405:   fldl 0x8048580
0804840b:   fstpl 0x8(%esp)
0804840f:   fldl 0x8048588
08048415:   fstpl (%esp)
08048418:   call 0x8048459 <compare<double>(double, double)>
0804841d:   fstpl 0x10(%esp)
13        	printf("v=%d,v2=%f", v, v2);
08048421:   fldl 0x10(%esp)
08048425:   fstpl 0x8(%esp)
08048429:   mov 0x1c(%esp),%eax
0804842d:   mov %eax,0x4(%esp)
08048431:   movl $0x8048570,(%esp)
08048438:   call 0x8048300 <printf@plt>
0804843d:   mov $0x0,%eax
14        }
08048442:   leave 
08048443:   ret 
 5        type compare(type a, type b)
          compare<int>(int, int):
08048444:   push %ebp
08048445:   mov %esp,%ebp
 7            return a > b ? a : b;
08048447:   mov 0x8(%ebp),%eax
0804844a:   cmp 0xc(%ebp),%eax
0804844d:   jle 0x8048454 <compare<int>(int, int)+16>
0804844f:   mov 0x8(%ebp),%eax
08048452:   jmp 0x8048457 <compare<int>(int, int)+19>
08048454:   mov 0xc(%ebp),%eax
 8        };
08048457:   pop %ebp
08048458:   ret 
 5        type compare(type a, type b)
          compare<double>(double, double):
08048459:   push %ebp
0804845a:   mov %esp,%ebp
0804845c:   sub $0x10,%esp
0804845f:   mov 0x8(%ebp),%eax
08048462:   mov %eax,-0x8(%ebp)
08048465:   mov 0xc(%ebp),%eax
08048468:   mov %eax,-0x4(%ebp)
0804846b:   mov 0x10(%ebp),%eax
0804846e:   mov %eax,-0x10(%ebp)
08048471:   mov 0x14(%ebp),%eax
08048474:   mov %eax,-0xc(%ebp)
 7            return a > b ? a : b;
08048477:   fldl -0x8(%ebp)
0804847a:   fldl -0x10(%ebp)
0804847d:   fxch %st(1)
0804847f:   fucomip %st(1),%st
08048481:   fstp %st(0)
08048483:   seta %al
08048486:   test %al,%al
08048488:   je 0x804848f <compare<double>(double, double)+54>
0804848a:   fldl -0x8(%ebp)
0804848d:   jmp 0x8048492 <compare<double>(double, double)+57>
0804848f:   fldl -0x10(%ebp)
 8        };
08048492:   leave 
08048493:   ret 

?

???? 汇编代码表明,两个compare调用的函数地址并不是一致的。其中整数的compare地址是0x8048444,而double的地址是 0x8048459。这说明编译器在编译的时候帮我们同时生成了两个compare函数。所以说,模板类的本质就是在编译器增加判断处理工作的同时,减 少手工的重复劳动。模板函数不需要显示定义函数的参数类型,这是因为可以从入参判断出函数的类型。

?

  • ?2. 模板类
???
#include <stdio.h>
#include <stdlib.h>

template<typename type>
class data_process {
	type a;
	type b;
public:
	data_process(type m, type n) :
			a(m), b(n) {
	}

	~data_process() {
	}
	type add() {
		return a + b;
	}
	type sub() {
		return a - b;
	}
};

int main(void) {
	data_process<int> data1(1,2);
	data_process<double> data2(1.2, 2.3);
	printf("v1=%d,v2=%f\n", data1.add(), data2.add());
}
?
          main():
080484f4:   push %ebp
080484f5:   mov %esp,%ebp
080484f7:   push %ebx
080484f8:   and $0xfffffff0,%esp
080484fb:   sub $0x50,%esp
24        	data_process<int> data1(1,2);
080484fe:   movl $0x2,0x8(%esp)
08048506:   movl $0x1,0x4(%esp)
0804850e:   lea 0x48(%esp),%eax
08048512:   mov %eax,(%esp)
08048515:   call 0x80485b4 <data_process<int>::data_process(int, int)>
25        	data_process<double> data2(1.2, 2.3);
0804851a:   fldl 0x8048710
08048520:   fstpl 0xc(%esp)
08048524:   fldl 0x8048718
0804852a:   fstpl 0x4(%esp)
0804852e:   lea 0x38(%esp),%eax
08048532:   mov %eax,(%esp)
08048535:   call 0x80485d0 <data_process<double>::data_process(double, double)>
26        	printf("v1=%d,v2=%f\n", data1.add(), data2.add());
0804853a:   lea 0x38(%esp),%eax
0804853e:   mov %eax,(%esp)
08048541:   call 0x804861a <data_process<double>::add()>
08048546:   fstpl 0x28(%esp)
0804854a:   lea 0x48(%esp),%eax
0804854e:   mov %eax,(%esp)
08048551:   call 0x8048608 <data_process<int>::add()>
08048556:   fldl 0x28(%esp)
0804855a:   fstpl 0x8(%esp)
0804855e:   mov %eax,0x4(%esp)
08048562:   movl $0x8048700,(%esp)
08048569:   call 0x8048410 <printf@plt>
0804856e:   lea 0x38(%esp),%eax
08048572:   mov %eax,(%esp)
08048575:   call 0x8048602 <data_process<double>::~data_process()>
0804857a:   lea 0x48(%esp),%eax
0804857e:   mov %eax,(%esp)
08048581:   call 0x80485ca <data_process<int>::~data_process()>
08048586:   mov $0x0,%eax
27        }
0804858b:   mov -0x4(%ebp),%ebx
0804858e:   leave 
0804858f:   ret 
08048590:   mov %eax,%ebx
26        	printf("v1=%d,v2=%f\n", data1.add(), data2.add());
08048592:   lea 0x38(%esp),%eax
08048596:   mov %eax,(%esp)
08048599:   call 0x8048602 <data_process<double>::~data_process()>
0804859e:   lea 0x48(%esp),%eax
080485a2:   mov %eax,(%esp)
080485a5:   call 0x80485ca <data_process<int>::~data_process()>
080485aa:   mov %ebx,%eax
080485ac:   mov %eax,(%esp)
080485af:   call 0x8048430 <_Unwind_Resume@plt>
 9        	data_process(type m, type n) :
          data_process<int>::data_process(int, int):
080485b4:   push %ebp
080485b5:   mov %esp,%ebp
10        			a(m), b(n) {
080485b7:   mov 0x8(%ebp),%eax
080485ba:   mov 0xc(%ebp),%edx
080485bd:   mov %edx,(%eax)
080485bf:   mov 0x8(%ebp),%eax
080485c2:   mov 0x10(%ebp),%edx
080485c5:   mov %edx,0x4(%eax)
11        	}
080485c8:   pop %ebp
080485c9:   ret 
13        	~data_process() {
          data_process<int>::~data_process():
080485ca:   push %ebp
080485cb:   mov %esp,%ebp
14        	}
080485cd:   pop %ebp
080485ce:   ret 
080485cf:   nop 
 9        	data_process(type m, type n) :
          data_process<double>::data_process(double, double):
080485d0:   push %ebp
080485d1:   mov %esp,%ebp
080485d3:   sub $0x10,%esp
080485d6:   mov 0xc(%ebp),%eax
080485d9:   mov %eax,-0x8(%ebp)
080485dc:   mov 0x10(%ebp),%eax
080485df:   mov %eax,-0x4(%ebp)
080485e2:   mov 0x14(%ebp),%eax
080485e5:   mov %eax,-0x10(%ebp)
080485e8:   mov 0x18(%ebp),%eax
080485eb:   mov %eax,-0xc(%ebp)
10        			a(m), b(n) {
080485ee:   mov 0x8(%ebp),%eax
080485f1:   fldl -0x8(%ebp)
080485f4:   fstpl (%eax)
080485f6:   mov 0x8(%ebp),%eax
080485f9:   fldl -0x10(%ebp)
080485fc:   fstpl 0x8(%eax)
11        	}
080485ff:   leave 
08048600:   ret 
08048601:   nop 
13        	~data_process() {
          data_process<double>::~data_process():
08048602:   push %ebp
08048603:   mov %esp,%ebp
14        	}
08048605:   pop %ebp
08048606:   ret 
08048607:   nop 
15        	type add() {
          data_process<int>::add():
08048608:   push %ebp
08048609:   mov %esp,%ebp
16        		return a + b;
0804860b:   mov 0x8(%ebp),%eax
0804860e:   mov (%eax),%edx
08048610:   mov 0x8(%ebp),%eax
08048613:   mov 0x4(%eax),%eax
08048616:   add %edx,%eax
17        	}
08048618:   pop %ebp
08048619:   ret 
15        	type add() {
          data_process<double>::add():
0804861a:   push %ebp
0804861b:   mov %esp,%ebp
16        		return a + b;
0804861d:   mov 0x8(%ebp),%eax
08048620:   fldl (%eax)
08048622:   mov 0x8(%ebp),%eax
08048625:   fldl 0x8(%eax)
08048628:   faddp %st,%st(1)
17        	}
0804862a:   pop %ebp
0804862b:   ret 
????? 针对每一个类型,模板的构造函数析构函数、成员函数都要独立生成,这从上面的函数地址就可以看出来。所以模板的本质就是对 不同数据类型的相似性操作进行共同属性提取,合成模板。在应用的时候,编译器根据我们使用中的数据类型独立生成每一个类,构建每一个基本运算变量和运算函 数,仅此而已。
发表评论
用户名: 匿名