高效的C編程之: 函數調用
14.9函數調用
函數設計的基本原則是使其函數體盡量的小。這樣編譯器可以對函數做更多的優化。
14.9.1減少函數調用開銷
ARM上的函數調用開銷比非RISC體系結構上的調用開銷?。?/p>
·調用返回指令“BL”或“MOVpc,lr”一般只需要6個指令周期(ARM7上)。
·在函數的入口和出口使用多寄存器加載/存儲指令LDM和STM(Thumb指令使用PUSH和POP)提高函數體的執行效率。
ARM體系結構過程調用標準AAPCS定義了如何通過寄存器傳遞參數和返回值。函數中的前4個整型參數是通過ARM的前4個寄存器r0、r1、r2和r3來傳遞的。傳遞參數可以是與整型兼容的數據類型,如字符類型char、半字類型short等。
注意 | 如果是雙字類型,如longlong型,只能通過寄存器傳遞兩個參數。 |
不能通過寄存器傳遞的參數,通過函數堆棧來傳遞。這樣不論是函數的調用者還是被調用者都必須通過訪問堆棧來訪問參數,使程序的執行效率下降。
下面的例子顯示了函數調用是傳遞4個參數和多于4個參數的區別。
傳遞4個參數的函數調用源文件如下。
intfunc1(inta,intb,intc,intd)
{
returna+b+c+d;
}
intcaller1(void)
{
returnfunc1(1,2,3,4);
}
編譯的結果如下。
func1
ADDr0,r0,r1
ADDr0,r0,r2
ADDr0,r0,r3
MOVpc,lr
caller1
MOVr3,#4
MOVr2,#3
MOVr1,#2
MOVr0,#1
Bfunc1
如果程序需要傳遞6個參數,變為如下形式。
intfunc2(inta,intb,intc,intd,inte,intf)
{
returna+b+c+d+e+f;
}
intcaller2(void)
{
returnfunc1(1,2,3,4,5,6);
}
則編譯后的匯編文件如下。
func2
STRlr,[sp,#-4]!
ADDr0,r0,r1
ADDr0,r0,r2
ADDr0,r0,r3
LDMIBsp,{r12,r14}
ADDr0,r0,r12
ADDr0,r0,r14
LDRpc,{sp},#4
caller2
STMFDsp!,{r2,r3,lr}
MOVr3,#6
MOVr2,#5
STMIAsp,{r2,r3}
MOVr3,#4
MOVr2,#3
MOVr1,#2
MOVr0,#1
BLfunc2
LDMFDsp!,{r2,r3,pc}
綜上所述,為了在程序中高效的調用函數,最好遵循以下規則。
·盡量限制函數的參數,不要超過4個,這樣函數調用的效率會更高。
·當傳遞的參數超過4個時,要將多個相關參數組織在一個結構體中,用傳遞結構體指針來代替多個參數。
·避免將傳遞的參數定義為longlong型,因為傳遞一個longlong型的數據將會占用兩個32位寄存器。
·函數中存在浮點運算時,避免使用double型參數。
評論