C++编译器函数模版机制剖析 - 函数模版的本质
思考:为什么函数模板能够和函数重载放在一块。C++编译器是怎样提供函数模板机制的?
demo 1
#include <cstdio>
#include <iostream>
using namespace std; // 1.cpp // g++ -S 1.cpp -o 1.s
template <typename T>
void myswap(T &a, T &b)
{
T c = 0;
c = a;
a = b;
b = c;
cout << "hello ....我是模板函数 欢迎 calll 我" << endl;
} int main()
{
{ int x = 10;
int y = 20; myswap<int>(x, y); //1 函数模板 显示类型 调用 printf("x:%d y:%d \n", x, y);
} {
char a = 'a';
char b = 'b'; myswap<char>(a, b); //1 函数模板 显示类型 调用
printf("a:%c b:%c \n", a, b);
}
return 0;
}
把demo 1编译成汇编文件,查看:
.file "1.cpp"
.lcomm __ZStL8__ioinit,1,1
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "x:%d y:%d \12\0"
LC1:
.ascii "a:%c b:%c \12\0"
.def ___gxx_personality_sj0; .scl 2; .type 32; .endef
.def __Unwind_SjLj_Register; .scl 2; .type 32; .endef
.def __Unwind_SjLj_Unregister; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
pushl %edi
pushl %esi
pushl %ebx
andl $-16, %esp
subl $96, %esp
movl $___gxx_personality_sj0, 52(%esp)
movl $LLSDA959, 56(%esp)
leal 60(%esp), %eax
movl %ebp, (%eax)
movl $L5, %edx
movl %edx, 4(%eax)
movl %esp, 8(%eax)
leal 28(%esp), %eax
movl %eax, (%esp)
call __Unwind_SjLj_Register
call ___main
movl $10, 92(%esp)
movl $20, 88(%esp)
leal 88(%esp), %eax
movl %eax, 4(%esp)
leal 92(%esp), %eax
movl %eax, (%esp)
movl $1, 32(%esp)
<span style="color:#ff0000;"> call __Z6myswapIiEvRT_S1_ // 41 call 117</span>
movl 88(%esp), %edx
movl 92(%esp), %eax
movl %edx, 8(%esp)
movl %eax, 4(%esp)
movl $LC0, (%esp)
call _printf
movb $97, 87(%esp)
movb $98, 86(%esp)
leal 86(%esp), %eax
movl %eax, 4(%esp)
leal 87(%esp), %eax
movl %eax, (%esp)
movl $2, 32(%esp)
<span style="color:#ff0000;"> call __Z6myswapIcEvRT_S1_ // 55 call 145</span>
movb 86(%esp), %al
movsbl %al, %edx
movb 87(%esp), %al
movsbl %al, %eax
movl %edx, 8(%esp)
movl %eax, 4(%esp)
movl $LC1, (%esp)
call _printf
movl $0, %eax
movl %eax, 24(%esp)
jmp L8
L5:
movl 36(%esp), %edx
movl 32(%esp), %eax
testl %eax, %eax
je L6
cmpl $1, %eax
je L7
.word 0x0b0f
L6:
movl %edx, %eax
movl %eax, (%esp)
movl $-1, 32(%esp)
call __Unwind_SjLj_Resume
L7:
movl %edx, %eax
movl %eax, (%esp)
movl $-1, 32(%esp)
call __Unwind_SjLj_Resume
L8:
leal 28(%esp), %eax
movl %eax, (%esp)
call __Unwind_SjLj_Unregister
movl 24(%esp), %eax
leal -12(%ebp), %esp
popl %ebx
popl %esi
popl %edi
popl %ebp
ret
.section .gcc_except_table,"w"
LLSDA959:
.byte 0xff
.byte 0xff
.byte 0x1
.uleb128 LLSDACSE959-LLSDACSB959
LLSDACSB959:
.uleb128 0
.uleb128 0
.uleb128 0x1
.uleb128 0
LLSDACSE959:
.text
.section .rdata,"dr"
.align 4
LC2:
.ascii "hello ....\316\322\312\307\304\243\260\345\272\257\312\375 \273\266\323\255 calll \316\322\0"
.section .text$_Z6myswapIiEvRT_S1_,"x"
.linkonce discard
.globl __Z6myswapIiEvRT_S1_
.def __Z6myswapIiEvRT_S1_; .scl 2; .type 32; .endef
<span style="color:#ff0000;">__Z6myswapIiEvRT_S1_: // 117</span>
pushl %ebp
movl %esp, %ebp
subl $40, %esp
movl $0, -12(%ebp)
movl 8(%ebp), %eax
movl (%eax), %eax
movl %eax, -12(%ebp)
movl 12(%ebp), %eax
movl (%eax), %edx
movl 8(%ebp), %eax
movl %edx, (%eax)
movl 12(%ebp), %eax
movl -12(%ebp), %edx
movl %edx, (%eax)
movl $LC2, 4(%esp)
movl $__ZSt4cout, (%esp)
call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, (%esp)
movl %eax, %ecx
call __ZNSolsEPFRSoS_E
subl $4, %esp
leave
ret
.section .text$_Z6myswapIcEvRT_S1_,"x"
.linkonce discard
.globl __Z6myswapIcEvRT_S1_
.def __Z6myswapIcEvRT_S1_; .scl 2; .type 32; .endef
<span style="color:#ff0000;">__Z6myswapIcEvRT_S1_: // 145</span>
pushl %ebp
movl %esp, %ebp
subl $40, %esp
movb $0, -9(%ebp)
movl 8(%ebp), %eax
movb (%eax), %al
movb %al, -9(%ebp)
movl 12(%ebp), %eax
movb (%eax), %dl
movl 8(%ebp), %eax
movb %dl, (%eax)
movl 12(%ebp), %eax
movb -9(%ebp), %dl
movb %dl, (%eax)
movl $LC2, 4(%esp)
movl $__ZSt4cout, (%esp)
call __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, (%esp)
movl %eax, %ecx
call __ZNSolsEPFRSoS_E
subl $4, %esp
leave
ret
.text
.def ___tcf_0; .scl 3; .type 32; .endef
___tcf_0:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $__ZStL8__ioinit, %ecx
call __ZNSt8ios_base4InitD1Ev
leave
ret
.def __Z41__static_initialization_and_destruction_0ii; .scl 3; .type 32; .endef
__Z41__static_initialization_and_destruction_0ii:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
cmpl $1, 8(%ebp)
jne L12
cmpl $65535, 12(%ebp)
jne L12
movl $__ZStL8__ioinit, %ecx
call __ZNSt8ios_base4InitC1Ev
movl $___tcf_0, (%esp)
call _atexit
L12:
leave
ret
.def __GLOBAL__sub_I_main; .scl 3; .type 32; .endef
__GLOBAL__sub_I_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $65535, 4(%esp)
movl $1, (%esp)
call __Z41__static_initialization_and_destruction_0ii
leave
ret
.section .ctors,"w"
.align 4
.long __GLOBAL__sub_I_main
.def __Unwind_SjLj_Resume; .scl 2; .type 32; .endef
.def _printf; .scl 2; .type 32; .endef
.def __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_; .scl 2; .type 32; .endef
.def __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc; .scl 2; .type 32; .endef
.def __ZNSolsEPFRSoS_E; .scl 2; .type 32; .endef
.def __ZNSt8ios_base4InitD1Ev; .scl 2; .type 32; .endef
.def __ZNSt8ios_base4InitC1Ev; .scl 2; .type 32; .endef
.def _atexit; .scl 2; .type 32; .endef
观察发现一个现象,myswap函数模版有一个声明,两个定义,这样的情况和我在“为什么会有函数模版中”博文中提到的两个myswap函数非常相似,实际这里体现了C++实现函数模版的本。本来须要程序猿依据须要去写非常多个逻辑同样,參数不同的函数。可是C++编译器帮我们做了这件事,依据调用会自己主动生成这些函数。这也是为什么函数模版能够和普通函数放在一起。
总结:函数模版机制结论:
编译器并非把函数模版处理成可以处理随意类的函数;
编译器从函数模版通过详细类型产生不同的函数;
编译器会对函数模版进行两次编译:在声明的地方对模版代码本身进行编译,在调用的地方对參数替换后的代码进行编译。
C++编译器函数模版机制剖析 - 函数模版的本质的更多相关文章
- Web API 处理机制剖析 --- 拨开迷雾看本质
前言 最近开发了几个项目,用到了web api,也通过项目加深了对web api的理解.本文试图从内部原理讲解web api的本质.透过重重迷雾,看清本质,就能更好的把握和利用好web api. 1 ...
- C++中函数模版和普通函数的区别
函数模版和同名普通函数在同一个作用域中,会优先调用那个函数? 函数模型在进行调用的时候会进行严格的类型匹配,而普通函数在调用的时候,会进行函数参数类型转换(前提是自动类型转换). 调用函数模版,本质是 ...
- C++ 类模板二(类模版与友元函数)
//类模版与友元函数 #include<iostream> using namespace std; template<typename T> class Complex{ p ...
- malloc 函数工作机制(转)
malloc()工作机制 malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表.调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块.然后,将 ...
- C++编译器模板机制剖析
思考:为什么函数模板可以和函数重载放在一块.C++编译器是如何提供函数模板机制的? 一.编译器编译原理 什么是gcc gcc(GNU C Compiler)编译器的作者是Richard Stallma ...
- Python 函数参数传递机制.
learning python,5e中讲到.Python的函数参数传递机制是对象引用. Arguments are passed by assignment (object reference). I ...
- day11(函数参数,函数对象,打散机制,函数嵌套调用)
一,复习 # 什么是函数:具体特定功能的代码块 - 特定功能代码块作为一个整体,并给该整体命名,就是函数 # 函数的优点: # 1.减少代码的冗余 # 2.结构清晰,可读性强 # 3.具有复用性,开发 ...
- 多线程中的信号机制--signwait()函数【转】
本文转载自:http://blog.csdn.net/yusiguyuan/article/details/14237277 在Linux的多线程中使用信号机制,与在进程中使用信号机制有着根本的区别, ...
- Mqtt paho 回调函数触发机制跟踪
Python Mqtt paho 回调函数触发机制跟踪,我使用的是 buildroot 里面的 mqtt paho , 代码在 ''' buildroot-2017.02.8/output/build ...
随机推荐
- ZOJ 3603 Draw Something Cheat
点我看题目 题意 : 给你n个字符串,让你找出在每个字符串中出现的字母,按字典序输出来. 思路 :一开始想差了,以为记录下每个字符出现次数,然后找次数大于1的,可是我忘了可能在一个字符串中有AA,而另 ...
- Java 单链表逆序
代码: package com.wangzhu.linkedlist; public class LinkedListDemo { /** * @param args */ public static ...
- IBInspectable的使用
IBInspectable的使用 创建一个分类 定义属性 把此分类的头文件引入到pch里面 此时查看属性面板 就有了可以供我们勾选的选项 在.m中实现一下set和get方法
- 李洪强iOS开发之提交AppStory时候遇到的坑
今天我在上传AppStore的时候,遇到了很多的问题.一直找不到问题的原因,但是最后终于发现问题的原因 ,是因为钥匙串签名无效的问题,解决方案如下: 证书签名无效解决: 1,按照你那个链接下载,htt ...
- VMware与宿敌Amazon一笑泯恩仇:重新定义混合云?(私有云节节败退)
摘要: 私有云巨头VMware看来是真的要输给一个“书贩子” 了!这意味着私有云将败给公有云? [阅读原文] 三年前,虚拟化巨头VMware曾对亚马逊Amazon云服务AWS竖过中指:我们怎么可能打不 ...
- tomcat docBase 和 path
<Context docBase="zjzc-web-api" path="/api" reloadable="false"/> ...
- linux多线程驱动中调用udelay()对整个系统造成的影响(by liukun321咕唧咕唧)
以前没考虑过这个问题,而且之前可能运气比较好,虽然用了udelay但也没出什么奇怪的问题,今天在 CSDN上看到了一篇关于此问题帖子,觉得很受用,再此做简要的记录和分析: 驱动开的是内核线程 跟普通进 ...
- PHP ‘scan’函数拒绝服务漏洞
漏洞名称: PHP ‘scan’函数拒绝服务漏洞 CNNVD编号: CNNVD-201311-464 发布时间: 2013-12-06 更新时间: 2013-12-06 危害等级: 中危 漏洞类型 ...
- 转自 z55250825 的几篇关于FFT的博文(三)
题目大意:给出n个数qi,定义 Fj为 令 Ei=Fi/qi,求Ei. 其实这道题就是看到有FFT模板才觉得有必要学一下的... 所以实际上就是已经知道题解了... = ...
- jquery插件cloud-zoom(放大镜)
效果预览:http://www.helloweba.com/demo/cloud-zoom/ 源代码下载:http://pan.baidu.com/s/1eQnadXo Cloud Zoom是一个图像 ...