`
jimmee
  • 浏览: 535984 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

从汇编角度看C++模板

阅读更多
  • 1. 模板函数         

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

        模板函数的反汇编示例:

    

#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 
      针对每一个类型,模板的构造函数、析构函数、成员函数都要独立生成,这从上面的函数地址就可以看出来。所以模板的本质就是对 不同数据类型的相似性操作进行共同属性提取,合成模板。在应用的时候,编译器根据我们使用中的数据类型独立生成每一个类,构建每一个基本运算变量和运算函 数,仅此而已。
分享到:
评论

相关推荐

    C++模板元编程 ppt - 荣耀

    ### C++模板元编程技术与应用 #### 一、历史背景 C++模板元编程(Template Metaprogramming,简称TMP)的历史可以追溯至1994年。在这年的一次C++标准委员会会议上,Erwin Unruh展示了一段特殊的代码,能够利用编译...

    面试基础知识整理(c++以及c).pdf

    《深入C++对象模型》、《STL源码剖析》以及《C和指针》、《C陷阱和缺陷》等书则从更深入的角度剖析了C++的对象模型、标准模板库的实现以及C和C++语言的高级特性及其潜在风险。阅读这些书籍可以加深对C++和C语言的...

    史上最全的C/C++笔试和面试题

    4. **面向对象编程**:C++是面向对象的语言,面试题可能包括类、对象、封装、继承、多态等概念,以及虚函数、模板、STL库的使用。 5. **异常处理**:C++中的try-catch语句和异常处理机制,以及何时应该使用异常处理...

    C++.zip

    由于没有具体的标签信息,我们可以从C++的基础知识、核心概念、编程实践等多个角度来探讨这个主题。 C++是一种强大的、面向对象的编程语言,由Bjarne Stroustrup于1979年在贝尔实验室开发,作为C语言的扩展。它在...

    C++编程思想(第2版)

    - **反向审视**:Eckel经常通过具体的例子引导读者从C++编译器的角度反向思考C++语言的实现原理,这种视角能够帮助读者深入理解语言特性。 - **澄清混淆点**:书中特别注重澄清学习过程中容易产生混淆的概念,通过...

    异构并行任务计算tbb

    4. **从汇编角度看C++编译器优化**:解析编译器如何进行自动优化,帮助理解代码的底层执行机制。 5. **C++11起的多线程编程**:介绍从mutex到无锁并行编程的方法,为并行编程打下坚实的基础。 6. **并行编程常用框架...

    ACM-ICOC培训资料汇编(7)计算几何

    - 在进行向量运算时,要注意不同运算的意义,比如利用点积判断角度关系,叉积判断旋转方向。 - 距离计算时,注意区分不同对象间的距离公式。 ##### 1.3 模板代码 - **点积计算**: ```cpp double dot(Vector a, ...

    linux编译器GCC编译手册

    - `"fsinx %1, %0"`:表示汇编指令模板,其中`%1`对应第一个参数(输入角度),`%0`对应第二个参数(结果)。 - `": "=f" (result)"`:指定输出变量约束。`"=f"`表示该变量会被存储在一个浮点寄存器中,并且会被...

    C/C++ 数组和指针及引用的区别

    (3)汇编角度: - 初始化引用`int &a = i;`,`lea eax,[i]`获取i的地址,然后`mov dword ptr [a],eax`看似将地址存入a的内存,实际上这只是将地址赋值给引用a,a并没有独立的存储空间。 总结来说,数组、指针和...

    农业机械毕业生简历模板.doc

    2. **计算机技能**:除了专业课程,他还学习了计算机相关的课程,如计算机组织与结构、硬件及接口电路设计、汇编语言、C/C++程序设计、软件工程以及计算机网络原理,这表明他在IT领域有扎实的基础,能够进行软件开发...

    vc++6.0 多文档,多视图

    1. **创建MDI工程**:在Visual C++ 6.0的"新建"对话框中,选择"工程" -&gt; "MFC应用程序",然后在向导中选择"MDI应用程序"模板。 2. **设计视图类**:为每个视图创建一个继承自CView的类,定义并实现视图特定的绘图和...

    c程序开发中长见问题50条

    ** 从纯粹的数据封装角度,友元确实打破了封装规则,因为它暴露了类的内部细节。但在实际应用中,适当使用友元可以简化代码设计,只要控制好访问权限,避免滥用,友元仍然是一种有用的机制。 #### 提高篇:进阶C++...

    数据结构(C#语言版)

    ### 数据结构(C#语言版)知识点解析 #### 一、数据结构教材的选择与现状 - **背景**: 自从美国唐·欧·克努特教授用汇编语言编写了...无论是从理论学习还是实际操作的角度来看,本书都能够提供全面的支持和指导。

    holamundo-OzdyMonreal-1:由GitHub Classroom创建的holamundo-OzdyMonreal-1

    从C++的角度,我们可以探讨以下知识点: 1. **基本语法**:包括变量声明、数据类型(如int, char, float, double等)、操作符(如+,-,*,/,==,!=等)、控制结构(if-else, switch-case, for, while循环)。 2....

    2024嵌入式大厂面经算法面试题总结

    综上所述,为了更好地准备2024年的嵌入式大厂面试,需要从多个角度进行准备,不仅要加强理论知识的学习,还要注重实践能力的培养。同时,持续关注技术动态,不断提升自身的技术水平和个人能力。

    操作系统(内存管理)

    那样,从调用程序的角度来看,它们所得到的全部是空闲的、开放的内存。然后,当通过 free() 将该指针传递回来时,我们只需要倒退几个内存字节就可以再次找到这个结构。 在讨论分配内存之前,我们将先讨论释放,...

    C#微软培训资料

    18.2 在 C #代码中调用 C++和 VB 编写的组件 .240 18.3 版 本 控 制 .249 18.4 代 码 优 化 .252 18.5 小 结 .254 第五部分 附 录 .255 附录 A 关 键 字.255 附录 B 错 误 码.256 附录 C .Net 名字空间...

Global site tag (gtag.js) - Google Analytics