為什麼不建議函式有太多引數?

東北碼農 發表於 2022-01-28

記錄一篇今天工作的思考。為什麼不建議函式的有太多引數?


今天做組內程式碼評審時,發現同事的程式碼有一個小問題,一個函式新增了一個引數後有了7個引數,而公司的編碼規範要求,函式的引數不許超過6個。

後來我就研究了一下,為啥不建議函式有太多引數呢?當然函式引數太多,不利於維護,學習成本比較高。除此之外,函式引數太多對效能也有一定的影響。


觀察引數傳遞方式

我做了一個實驗,觀察對含有6個、7個、8個引數的函式進行呼叫時,到底有哪些不同,測試程式碼如下:

#include <iostream>

void func6(int p1, int p2, int p3, int p4, int p5,
           int p6)
{
}

void func7(int p1, int p2, int p3, int p4, int p5,
           int p6, int p7)
{
}

void func8(int p1, int p2, int p3, int p4, int p5,
           int p6, int p7, int p8)
{
}

int main()
{
    func6(1, 2, 3, 4, 5, 6);
    func7(1, 2, 3, 4, 5, 6, 7);
    func8(1, 2, 3, 4, 5, 6, 7, 8);
    return 0;
}

我們檢視彙編程式碼,來觀察呼叫時如何傳遞引數。

我們看一下func6的呼叫,全部通過暫存器傳遞。

   0x00005555555551ce <+8>:     mov    r9d,0x6
   0x00005555555551d4 <+14>:    mov    r8d,0x5
   0x00005555555551da <+20>:    mov    ecx,0x4
   0x00005555555551df <+25>:    mov    edx,0x3
   0x00005555555551e4 <+30>:    mov    esi,0x2
   0x00005555555551e9 <+35>:    mov    edi,0x1
   0x00005555555551ee <+40>:    call   0x555555555169 <func6(int, int, int, int, int, int)>

我們看一下func7的呼叫,引數1~6通過暫存器,引數7通過堆疊傳遞。


   0x00005555555551f3 <+45>:    push   0x7
   0x00005555555551f5 <+47>:    mov    r9d,0x6
   0x00005555555551fb <+53>:    mov    r8d,0x5
   0x0000555555555201 <+59>:    mov    ecx,0x4
   0x0000555555555206 <+64>:    mov    edx,0x3
   0x000055555555520b <+69>:    mov    esi,0x2
   0x0000555555555210 <+74>:    mov    edi,0x1
   0x0000555555555215 <+79>:    call   0x555555555188 <func7(int, int, int, int, int, int, int)>

我們看一下func8的呼叫,引數16通過暫存器,引數78通過堆疊傳遞。

   0x000055555555521e <+88>:    push   0x8
   0x0000555555555220 <+90>:    push   0x7
   0x0000555555555222 <+92>:    mov    r9d,0x6
   0x0000555555555228 <+98>:    mov    r8d,0x5
   0x000055555555522e <+104>:   mov    ecx,0x4
   0x0000555555555233 <+109>:   mov    edx,0x3
   0x0000555555555238 <+114>:   mov    esi,0x2
   0x000055555555523d <+119>:   mov    edi,0x1
   0x0000555555555242 <+124>:   call   0x5555555551a7 <func8(int, int, int, int, int, int, int, int)>

結論

gcc編譯器(gcc9),在x64環境下。函式呼叫時,前6個引數通過暫存器傳遞,超過6個後面的引數通過堆疊傳遞。而暫存器傳遞引數比堆疊傳遞效率高,所以建議函式引數不要超過6個。

學習c++還是要學習一些彙編的,可以解決很多問題啊。


最後,東北碼農,全網同名,求關注、點贊、轉發,謝謝~