C++编译器模板机制剖析
思考:为什么函数模板可以和函数重载放在一块。C++编译器是如何提供函数模板机制的?
一、编译器编译原理
什么是gcc
gcc(GNU C Compiler)编译器的作者是Richard Stallman,也是GNU项目的奠基者。 |
什么是gcc:gcc是GNU Compiler Collection的缩写。最初是作为C语言的编译器(GNU C Compiler),现在已经支持多种语言了,如C、C++、Java、Pascal、Ada、COBOL语言等。 |
gcc支持多种硬件平台,甚至对Don Knuth 设计的 MMIX 这类不常见的计算机都提供了完善的支持 |
gcc主要特征
1)gcc是一个可移植的编译器,支持多种硬件平台 2)gcc不仅仅是个本地编译器,它还能跨平台交叉编译。 3)gcc有多种语言前端,用于解析不同的语言。 4)gcc是按模块化设计的,可以加入新语言和新CPU架构的支持 5)gcc是自由软件 |
gcc编译过程
预处理(Pre-Processing) 编译(Compiling) 汇编(Assembling) 链接(Linking) Gcc *.c –o 1exe (总的编译步骤) Gcc –E 1.c –o 1.i //宏定义 宏展开 Gcc –S 1.i –o 1.s Gcc –c 1.s –o 1.o Gcc 1.o –o 1exe 结论:gcc编译工具是一个工具链。。。。 |
图:程序编译流程
解析:hello程序是一个高级C语言程序,这种形式容易被人读懂。为了在系统上运行hello.c程序,每条C语句都必须转化为低级机器指令。然后将这些指令打包成可执行目标文件格式,并以二进制形式存储器于磁盘中。
gcc常用编译选项
选项 |
作用 |
-o |
产生目标(.i、.s、.o、可执行文件等) |
-c |
通知gcc取消链接步骤,即编译源码并在最后生成目标文件 |
-E |
只运行C预编译器 |
-S |
告诉编译器产生汇编语言文件后停止编译,产生的汇编语言文件扩展名为.s |
-Wall |
使gcc对源文件的代码有问题的地方发出警告 |
-Idir |
将dir目录加入搜索头文件的目录路径 |
-Ldir |
将dir目录加入搜索库的目录路径 |
-llib |
链接lib库 |
-g |
在目标文件中嵌入调试信息,以便gdb之类的调试程序调试 |
练习
gcc -E hello.c -o hello.i(预处理) gcc -S hello.i -o hello.s(编译) gcc -c hello.s -o hello.o(汇编) gcc hello.o -o hello(链接) 以上四个步骤,可合成一个步骤 gcc hello.c -o hello(直接编译链接成可执行目标文件) gcc -c hello.c或gcc -c hello.c -o hello.o(编译生成可重定位目标文件) |
建议初学都加这个选项。下面这个例子如果不加-Wall选项编译器不报任何错误,但是得到的结果却不是预期的。 #include <stdio.h> int main(void) { printf("2+1 is %f", 3); return 0; } |
Gcc编译多个.c |
hello_1.h hello_1.c main.c 一次性编译 gcc hello_1.c main.c –o newhello 独立编译 gcc -Wall -c main.c -o main.o gcc -Wall -c hello_1.c -o hello_fn.o gcc -Wall main.o hello_1.o -o newhello |
二、模板函数反汇编观察
命令:g++ -S 7.cpp -o 7.s
- .file "7.cpp"
- .text
- .def __ZL6printfPKcz; .scl 3; .type 32; .endef
- __ZL6printfPKcz:
- LFB264:
- .cfi_startproc
- pushl %ebp
- .cfi_def_cfa_offset 8
- .cfi_offset 5, -8
- movl %esp, %ebp
- .cfi_def_cfa_register 5
- pushl %ebx
- subl $36, %esp
- .cfi_offset 3, -12
- leal 12(%ebp), %eax
- movl %eax, -12(%ebp)
- movl -12(%ebp), %eax
- movl %eax, 4(%esp)
- movl 8(%ebp), %eax
- movl %eax, (%esp)
- call ___mingw_vprintf
- movl %eax, %ebx
- movl %ebx, %eax
- addl $36, %esp
- popl %ebx
- .cfi_restore 3
- popl %ebp
- .cfi_restore 5
- .cfi_def_cfa 4, 4
- ret
- .cfi_endproc
- LFE264:
- .lcomm __ZStL8__ioinit,1,1
- .def ___main; .scl 2; .type 32; .endef
- .section .rdata,"dr"
- LC0:
- .ascii "a:%d b:%d \12\0"
- LC1:
- .ascii "c1:%c c2:%c \12\0"
- LC2:
- .ascii "pause\0"
- .text
- .globl _main
- .def _main; .scl 2; .type 32; .endef
- _main:
- LFB1023:
- .cfi_startproc
- .cfi_personality 0,___gxx_personality_v0
- .cfi_lsda 0,LLSDA1023
- pushl %ebp
- .cfi_def_cfa_offset 8
- .cfi_offset 5, -8
- movl %esp, %ebp
- .cfi_def_cfa_register 5
- andl $-16, %esp
- subl $32, %esp
- call ___main
- movl $0, 28(%esp)
- movl $10, 24(%esp)
- movb $97, 23(%esp)
- movb $98, 22(%esp)
- leal 24(%esp), %eax
- movl %eax, 4(%esp)
- leal 28(%esp), %eax
- movl %eax, (%esp)
- call __Z6myswapIiEvRT_S1_ //66 ===>126
- movl 24(%esp), %edx
- movl 28(%esp), %eax
- movl %edx, 8(%esp)
- movl %eax, 4(%esp)
- movl $LC0, (%esp)
- call __ZL6printfPKcz
- leal 22(%esp), %eax
- movl %eax, 4(%esp)
- leal 23(%esp), %eax
- movl %eax, (%esp)
- call __Z6myswapIcEvRT_S1_ //77 ===>155
- movzbl 22(%esp), %eax
- movsbl %al, %edx
- movzbl 23(%esp), %eax
- movsbl %al, %eax
- movl %edx, 8(%esp)
- movl %eax, 4(%esp)
- movl $LC1, (%esp)
- call __ZL6printfPKcz
- movl $LC2, (%esp)
- LEHB0:
- call _system
- LEHE0:
- movl $0, %eax
- jmp L7
- L6:
- movl %eax, (%esp)
- LEHB1:
- call __Unwind_Resume
- LEHE1:
- L7:
- leave
- .cfi_restore 5
- .cfi_def_cfa 4, 4
- ret
- .cfi_endproc
- LFE1023:
- .def ___gxx_personality_v0; .scl 2; .type 32; .endef
- .section .gcc_except_table,"w"
- LLSDA1023:
- .byte 0xff
- .byte 0xff
- .byte 0x1
- .uleb128 LLSDACSE1023-LLSDACSB1023
- LLSDACSB1023:
- .uleb128 LEHB0-LFB1023
- .uleb128 LEHE0-LEHB0
- .uleb128 L6-LFB1023
- .uleb128 0
- .uleb128 LEHB1-LFB1023
- .uleb128 LEHE1-LEHB1
- .uleb128 0
- .uleb128 0
- LLSDACSE1023:
- .text
- .section .text$_Z6myswapIiEvRT_S1_,"x"
- .linkonce discard
- .globl __Z6myswapIiEvRT_S1_
- .def __Z6myswapIiEvRT_S1_; .scl 2; .type 32; .endef
- __Z6myswapIiEvRT_S1_: //126
- LFB1024:
- .cfi_startproc
- pushl %ebp
- .cfi_def_cfa_offset 8
- .cfi_offset 5, -8
- movl %esp, %ebp
- .cfi_def_cfa_register 5
- subl $16, %esp
- movl 8(%ebp), %eax
- movl (%eax), %eax
- movl %eax, -4(%ebp)
- movl 12(%ebp), %eax
- movl (%eax), %edx
- movl 8(%ebp), %eax
- movl %edx, (%eax)
- movl 12(%ebp), %eax
- movl -4(%ebp), %edx
- movl %edx, (%eax)
- leave
- .cfi_restore 5
- .cfi_def_cfa 4, 4
- ret
- .cfi_endproc
- LFE1024:
- .section .text$_Z6myswapIcEvRT_S1_,"x"
- .linkonce discard
- .globl __Z6myswapIcEvRT_S1_
- .def __Z6myswapIcEvRT_S1_; .scl 2; .type 32; .endef
- __Z6myswapIcEvRT_S1_: //155
- LFB1025:
- .cfi_startproc
- pushl %ebp
- .cfi_def_cfa_offset 8
- .cfi_offset 5, -8
- movl %esp, %ebp
- .cfi_def_cfa_register 5
- subl $16, %esp
- movl 8(%ebp), %eax
- movzbl (%eax), %eax
- movb %al, -1(%ebp)
- movl 12(%ebp), %eax
- movzbl (%eax), %edx
- movl 8(%ebp), %eax
- movb %dl, (%eax)
- movl 12(%ebp), %eax
- movzbl -1(%ebp), %edx
- movb %dl, (%eax)
- leave
- .cfi_restore 5
- .cfi_def_cfa 4, 4
- ret
- .cfi_endproc
- LFE1025:
- .text
- .def ___tcf_0; .scl 3; .type 32; .endef
- ___tcf_0:
- LFB1027:
- .cfi_startproc
- pushl %ebp
- .cfi_def_cfa_offset 8
- .cfi_offset 5, -8
- movl %esp, %ebp
- .cfi_def_cfa_register 5
- subl $8, %esp
- movl $__ZStL8__ioinit, %ecx
- call __ZNSt8ios_base4InitD1Ev
- leave
- .cfi_restore 5
- .cfi_def_cfa 4, 4
- ret
- .cfi_endproc
- LFE1027:
- .def __Z41__static_initialization_and_destruction_0ii; .scl 3; .type 32; .endef
- __Z41__static_initialization_and_destruction_0ii:
- LFB1026:
- .cfi_startproc
- pushl %ebp
- .cfi_def_cfa_offset 8
- .cfi_offset 5, -8
- movl %esp, %ebp
- .cfi_def_cfa_register 5
- subl $24, %esp
- cmpl $1, 8(%ebp)
- jne L11
- cmpl $65535, 12(%ebp)
- jne L11
- movl $__ZStL8__ioinit, %ecx
- call __ZNSt8ios_base4InitC1Ev
- movl $___tcf_0, (%esp)
- call _atexit
- L11:
- leave
- .cfi_restore 5
- .cfi_def_cfa 4, 4
- ret
- .cfi_endproc
- LFE1026:
- .def __GLOBAL__sub_I_main; .scl 3; .type 32; .endef
- __GLOBAL__sub_I_main:
- LFB1028:
- .cfi_startproc
- pushl %ebp
- .cfi_def_cfa_offset 8
- .cfi_offset 5, -8
- movl %esp, %ebp
- .cfi_def_cfa_register 5
- subl $24, %esp
- movl $65535, 4(%esp)
- movl $1, (%esp)
- call __Z41__static_initialization_and_destruction_0ii
- leave
- .cfi_restore 5
- .cfi_def_cfa 4, 4
- ret
- .cfi_endproc
- LFE1028:
- .section .ctors,"w"
- .align 4
- .long __GLOBAL__sub_I_main
- .ident "GCC: (rev2, Built by MinGW-builds project) 4.8.0"
- .def ___mingw_vprintf; .scl 2; .type 32; .endef
- .def _system; .scl 2; .type 32; .endef
- .def __Unwind_Resume; .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
函数模板机制结论
1.编译器并不是把函数模板处理成能够处理任意类的函数
2.编译器从函数模板通过具体类型产生不同的函数
3.编译器会对函数模板进行两次编译。在声明的地方对模板代码本身进行编译;在调用的地方对参数替换后的代码进行编译。
C++编译器模板机制剖析的更多相关文章
- C++编译器函数模版机制剖析 - 函数模版的本质
思考:为什么函数模板能够和函数重载放在一块.C++编译器是怎样提供函数模板机制的? demo 1 #include <cstdio> #include <iostream> u ...
- WPF源代码分析系列一:剖析WPF模板机制的内部实现(一)
众所周知,在WPF框架中,Visual类是可以提供渲染(render)支持的最顶层的类,所有可视化元素(包括UIElement.FrameworkElment.Control等)都直接或间接继承自Vi ...
- C#进阶系列——WebApi 路由机制剖析:你准备好了吗?
前言:从MVC到WebApi,路由机制一直是伴随着这些技术的一个重要组成部分. 它可以很简单:如果你仅仅只需要会用一些简单的路由,如/Home/Index,那么你只需要配置一个默认路由就能简单搞定: ...
- 【C#】 WebApi 路由机制剖析
C#进阶系列——WebApi 路由机制剖析:你准备好了吗? 转自:https://blog.csdn.net/wulex/article/details/71601478 2017年05月11日 10 ...
- C#进阶系列——WebApi 路由机制剖析:你准备好了吗? 转载https://www.cnblogs.com/landeanfen/p/5501490.html
阅读目录 一.MVC和WebApi路由机制比较 1.MVC里面的路由 2.WebApi里面的路由 二.WebApi路由基础 1.默认路由 2.自定义路由 3.路由原理 三.WebApi路由过程 1.根 ...
- WebApi 路由机制剖析
阅读目录 一.MVC和WebApi路由机制比较 1.MVC里面的路由 2.WebApi里面的路由 二.WebApi路由基础 1.默认路由 2.自定义路由 3.路由原理 三.WebApi路由过程 1.根 ...
- ectouch第七讲 之ECshop模板机制整理
网上的资源感觉还是有些用,可以看看,帮助理解,ECshop模板机制整理原文:http://blog.sina.com.cn/s/blog_6900af430100nkn8.html 一.模板引擎: E ...
- ECshop模板机制
ECshop模板机制整理 模板机制 近期新项目涉及到ECshop的二次开发,趁此良机正好可以对闻名已久的ECshop系统进行深入了解.要了解一个系统,那么该系统的模板机制就是最重要的一环.相关整理如下 ...
- Java反射机制剖析(四)-深度剖析动态代理原理及总结
动态代理类原理(示例代码参见java反射机制剖析(三)) a) 理解上面的动态代理示例流程 a) 理解上面的动态代理示例流程 b) 代理接口实现类源代码剖析 咱们一起来剖析一下代理实现类($Pr ...
随机推荐
- [图书] C++
作者 书名 Bjarne Stroustrup The Design and Evolution of C++Stanley B. Lippman C++ PrimerStanley B. ...
- “找女神要QQ号码”——java篇
题目就是这样的: 给了一串数字(不是QQ号码),根据下面规则可以找出QQ号码: 首先删除第一个数,紧接着将第二个数放到这串数字的末尾,再将第三个数删除,并将第四个数放到这串数字的末尾...... 如此 ...
- vim配置函数跳转(c/c++)
暂时草记一下,有时间好好整理 ctags 如果只是查看函数与变量是在哪里定义的,用ctags就可以了. ctrl+]跳到定义的地方,ctrl+t跳回来. 想要像IDE那样在旁边显示函数与变量列表,用t ...
- ubuntu部署nginx
先更新本机内置的程序. sudo apt-get updatesudo apt-get upgrade再判断系统是否内置了add-apt-repository命令,如果没有执行下列命令安装 sudo ...
- eclipse+gnuarm+使用报错
Description Resource Path Location TypeProgram "echo" not found in PATH stm32 Project Prop ...
- PAT天梯赛L2-003 月饼【贪心】
L2-003. 月饼 时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不 ...
- 微信都在用的移动敏捷测试方法和工具|视频+PPT
本文是腾讯优测总监雷彬在MPD2016 北京站上的演讲视频.他详细讲述了腾讯多年来在实践敏捷研发过程中测试的优化之路,为测试角色(包括测试工程师和开发自测)提供敏捷作业的思路.点击此处观看视频.时长5 ...
- Oracle中的时间函数用法(to_date、to_char) (总结)
一.24小时的形式显示出来要用HH24 select to_char(sysdate,'yyyy-MM-dd HH24:mi:ss') from dual; select to_date('2005- ...
- 冒泡排序之python
冒泡排序(Bubble sort) 两两比较相邻记录的关键字,如果反序则交换,直到没有反序记录为止. 1.算法描述: 比较相邻的元素.如果第一个比第二个大,就交换它们两个: 对每一对相邻元素作同样的工 ...
- 《前端JavaScript面试技巧》笔记一
思考: 拿到一个面试题,你第一时间看到的是什么 -> 考点 又如何看待网上搜出来的永远也看不完的题海 -> 不变应万变 如何对待接下来遇到的面试题 -> 题目到知识再到题目 知识体系 ...