• 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 
    ", x, y);
    	}
    
    
    	{
    		char a = 'a'; 
    		char b = 'b';
    
    		myswap<char>(a, b); //1 函数模板 显示类型 调用
    		printf("a:%c b:%c 
    ", 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"
    LC1:
    	.ascii "a:%c b:%c 12"
    	.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 ....316322312307304243260345272257312375 273266323255 calll 316322"
    	.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++编译器帮我们做了这件事,依据调用会自己主动生成这些函数。这也是为什么函数模版能够和普通函数放在一起。

    总结:函数模版机制结论:

    编译器并非把函数模版处理成可以处理随意类的函数;

    编译器从函数模版通过详细类型产生不同的函数;

    编译器会对函数模版进行两次编译:在声明的地方对模版代码本身进行编译,在调用的地方对參数替换后的代码进行编译。



  • 相关阅读:
    华为lab-rs-v1-2.11_OSPF与ISIS互通
    jdk源码分析红黑树——插入篇
    jdk源码分析PriorityQueue
    jdk源码分析ArrayDeque
    jdk链表笔记
    jdk顺序表笔记
    SpringMVC类型转换器、属性编辑器
    SpringMVC基本使用
    spring整合hibernate
    spring aop注解配置
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5336758.html
Copyright © 2020-2023  润新知