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 ...
随机推荐
- 严重: The web application [] registered the JDBC driver 错误
近日发现启动tomcat的时候报如下警告: -- :: org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc 严重: The ...
- *[topcoder]HexagonalBoard
http://community.topcoder.com/stat?c=problem_statement&pm=12784 真心觉得tc的div1 250不少好题,对我来说比较适合.这道题 ...
- Java泛型反射机制(二)
/** * @author Administrator * 好处:泛型:1安全 2减少代码重用率 */ package com.test; import java.lang.reflect.Metho ...
- 令人头疼的clientTop、scrollTop、offsetTop
1.网络上流传的图片 2.稍微容易理解点的示意图 参考链接:http://blog.csdn.net/lidiansheng/article/details/7950751 3.言简意赅的示意图 4. ...
- IPv6 tutorial 4 IPv6 address syntax
https://4sysops.com/archives/ipv6-tutorial-part-4-ipv6-address-syntax/ Now that you know about the n ...
- 应付系统选项 Payables Options
(N) AP > Setup > Options > Payables Options应付系统选项设置整个应付系统使用的控制项和默认值.我们可以在此窗口中设置默认值,从而简化供应商输 ...
- URAL1635. Mnemonics and Palindromes(DP)
链接 先初始化一下所有的回文串 再O(n*n)DP 输出路径dfs 刚开始存所有回文 ME了 后来发现用不着 改了改了OK了 数据还挺强 #include <iostream> #incl ...
- Grid表格属性
<Grid> <Grid.ColumnDefinitions> <!--添加列--> <ColumnDefinition Width="/> ...
- SCOI2007排列perm
1072: [SCOI2007]排列perm Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 805 Solved: 497[Submit][Stat ...
- C#使用SQLite出错:无法加载 DLL“SQLite.Interop.dll”,找不到指定的模块
在SQLite官方下载了System.Data.SQLite,编写如下测试代码: 复制内容到剪贴板 程序代码 using (SQLiteConnection conn = new SQLiteConn ...