用彙編的眼光看c (之模板函式)

2021-06-23 00:00:22 字數 4802 閱讀 4660

如果說模板類定義的是一種資料型別,那麼模板函式定義的就是一種函式。既然是函式,那麼就有輸入資料和輸出資料。和模板類的概念差不多,模板函式的初衷也是為了在函式操作上抽取共同的特性,遮蔽的是型別的不同和差異。我們可以通過下面乙個簡單的**說明問題:

[cpp]view plain

copy

intint_compare(

inta, 

intb)  

double

double_compare(

double

a, double

b)    

上面的一段**是取較大值的一段**。兩個函式之間最大的差別就是輸入資料型別和輸出資料型別之間的差別,那我們有沒有一種辦法可以遮蔽這種資料型別之間的差別呢?有。那就是函式模板:

[cpp]view plain

copy

template

<

typename

type>  

type compare(type a, type b)    

可以看到,模板函式和普通函式沒有什麼區別,只是在函式的上面把型別抽象成了type,那麼模板函式應該怎麼使用呢?

[cpp]view plain

copy

246:      

inti_value = compare(2, 3);  

00401458   push        3  

0040145a   push        2  

0040145c   call        @ilt+10(compare) (0040100f)  

00401461   add         esp,8  

00401464   mov         dword ptr [ebp-4],eax  

247:      double

d_value = compare(2.3, 3.1);  

00401467   push        4008cccch  

0040146c   push        0cccccccdh  

00401471   push        40026666h  

00401476   push        66666666h  

0040147b   call        @ilt+5(compare) (0040100a)  

00401480   add         esp,10h  

00401483   fstp        qword ptr [ebp-0ch]  

248:  }  

彙編**表明,兩個compare呼叫的函式位址並不是一致的。其中整數的compare位址是0x40100f,而double的位址是0x0040100a。這說明編譯器在編譯的時候幫我們同時生成了兩個compare函式。所以說,模板類的本質就是在編譯器增加判斷處理工作的同時,減少手工的重複勞動。同時和模板類不一樣,模板函式不需要顯示定義函式的引數型別,這是因為可以從入參判斷出函式的型別。

如果引數型別是 class型別呢? 我們可以試一試。首先定義基本class:

[cpp]view plain

copy

class

data  

~data() {}  

intget_value()   

intoperator > (data& d)   

};  

接著,我們呼叫compare函式:

[cpp]view plain

copy

256:      data m(4), n(2);  

0040148d   push        4  

0040148f   lea         ecx,[ebp-10h]  

00401492   call        @ilt+40(data::data) (0040102d)  

00401497   mov         dword ptr [ebp-4],0  

0040149e   push        2  

004014a0   lea         ecx,[ebp-14h]  

004014a3   call        @ilt+40(data::data) (0040102d)  

004014a8   mov         byte ptr [ebp-4],1  

257:      data p = compare(m,n);  

004014ac   mov         eax,dword ptr [ebp-14h]  

004014af   push        eax  

004014b0   mov         ecx,dword ptr [ebp-10h]  

004014b3   push        ecx  

004014b4   lea         edx,[ebp-18h]  

004014b7   push        edx  

004014b8   call        @ilt+15(compare) (00401014)  

004014bd   add         esp,0ch  

258:  }  

256行: data構造了兩個基本變數m和n

257行: 我們呼叫模板函式compare, 函式位址為0x401014,注意dx為p的位址,也就是堆疊臨時變數的位址

為了看到算術符》過載,我們跟進compare函式:

[cpp]view plain

copy

241:      

return

a > b ? a : b;  

0040212b   lea         eax,[ebp+10h]  

0040212e   push        eax  

0040212f   lea         ecx,[ebp+0ch]  

00402132   call        @ilt+55(data::operator>) (0040103c)  

00402137   test        eax,eax  

00402139   je          compare+53h (00402143)  

0040213b   lea         ecx,[ebp+0ch]  

0040213e   mov         dword ptr [ebp-18h],ecx  

00402141   jmp         compare+59h (00402149)  

00402143   lea         edx,[ebp+10h]  

00402146   mov         dword ptr [ebp-18h],edx  

00402149   mov         eax,dword ptr [ebp-18h]  

0040214c   mov         dword ptr [ebp-10h],eax  

0040214f   mov         ecx,dword ptr [ebp-10h]  

00402152   mov         edx,dword ptr [ecx]  

00402154   mov         eax,dword ptr [ebp+8]  

00402157   mov         dword ptr [eax],edx  

00402159   mov         ecx,dword ptr [ebp-14h]  

0040215c   or          ecx,1  

0040215f   mov         dword ptr [ebp-14h],ecx  

00402162   mov         byte ptr [ebp-4],1  

00402166   lea         ecx,[ebp+0ch]  

00402169   call        @ilt+25(data::~data) (0040101e)  

0040216e   mov         byte ptr [ebp-4],0  

00402172   lea         ecx,[ebp+10h]  

00402175   call        @ilt+25(data::~data) (0040101e)  

0040217a   mov         eax,dword ptr [ebp+8]  

我們發現compare模板語句下面構建了很多彙編語句,有一些冗長,我們可以大略介紹一下:

(1)  開頭呼叫call 0x0040103c函式就是呼叫過載運算子函式,[ebp-18h]表示即將被複製的是a資料還是b資料

(2) 比較返回結果後,開始複製資料,具體見0x402157,其中臨時變數[ebp-14h]和臨時變數[ebp-4]的操作可以忽略

(3) 函式返回前,對臨時變數a和b進行析構處理,見**0x402169和**0x402175。

注意:

(1)編寫模板函式前先保證自己的函式是編寫正確的

(2)模板函式的優先順序低於非模板函式

(3)模板函式的型別可以是自定義型別,也可以是c、c++語言的基本型別

(4)模板函式的使用經常和類的算術運算子混合使用,注意技巧

(5)模板函式中涉及指標部分的內容,務必注意

用彙編的眼光看c (之模板函式)

如果說模板類定義的是一種資料型別,那麼模板函式定義的就是一種函式。既然是函式,那麼就有輸入資料和輸出資料。和模板類的概念差不多,模板函式的初衷也是為了在函式操作上抽取共同的特性,遮蔽的是型別的不同和差異。我們可以通過下面乙個簡單的 說明問題 view plain intint compare int...

用彙編的眼光看c (之模板函式)

如果說模板類定義的是一種資料型別,那麼模板函式定義的就是一種函式。既然是函式,那麼就有輸入資料和輸出資料。和模板類的概念差不多,模板函式的初衷也是為了在函式操作上抽取共同的特性,遮蔽的是型別的不同和差異。我們可以通過下面乙個簡單的 說明問題 int int compare int a,int b d...

用彙編的眼光看c (之模板函式)

如果說模板類定義的是一種資料型別,那麼模板函式定義的就是一種函式。既然是函式,那麼就有輸入資料和輸出資料。和模板類的概念差不多,模板函式的初衷也是為了在函式操作上抽取共同的特性,遮蔽的是型別的不同和差異。我們可以通過下面乙個簡單的 說明問題 view plain int int compare in...