c/c++的函數參數壓棧順序

整理日:2015年3月18日c++

爲了這句話丟了不少次人.無所謂了,反正咱臉皮厚.函數

總結一下ui

編譯出來的c/c++程序的參數壓棧順序只和編譯器相關!this

下面列舉了一些常見的編譯器的調用約定指針

VC6code

調用約定 堆棧清除 參數傳遞
__cdecl 調用者 從右到左,經過堆棧傳遞
__stdcall 函數體 從右到左,經過堆棧傳遞
__fastcall 函數體 從右到左,優先使用寄存器(ECX,EDX),而後使用堆棧
thiscall 函數體 this指針默認經過ECX傳遞,其它參數從右到左入棧

__cdecl是CC++的默認調用約定; VC的調用約定中並無thiscall這個關鍵字,它是類成員函數默認調用約定;
CC++中的main(或wmain)函數的調用約定必須是__cdecl,不容許更改;
默認調用約定通常可以經過編譯器設置進行更改,若是你的代碼依賴於調用約定,請明確指出須要使用的調用約定;資源

C++Builder6編譯器

調用約定 堆棧清除 參數傳遞
__cdecl 調用者 從右到左,經過堆棧傳遞(與CC++默認調用約定兼容)
__stdcall 函數體 從右到左,經過堆棧傳遞(與VC中的__stdcall兼容)
__fastcall 函數體 從左到右,優先使用寄存器(EAX,EDX,ECX),而後使用堆棧 (兼容Delphi的register)
msfastcall 函數體 從右到左,優先使用寄存器(ECX,EDX),而後使用堆棧(兼容VC的__fastcall)
__pascal 函數體 從左到右,經過堆棧傳遞

因爲能力和資源有限,只能找到這些東西,主要的差別體如今fastcall上面,vc是前兩個參數放入寄存器,後面的壓棧,bcb是前3哥參數使用寄存器, 更有變態的,一個朋友朋友說有的參數超過7個之後前5個從左到右傳遞,後面的從右到走,上面說的不可不信,不可全信.源碼

如何肯定你的編譯採用的那種順序那?it

#include <stdio.h>
int f(int i,int j,int k);
int main()
{
    static int i=0;
    f(i++,i++,i++);
    return 0;
}

int f(int i,int j,int k)
{
    int l;
    int g;
    printf("k=%d:[%x] ",k,&k);
    printf("j=%d:[%x] ",j,&j);
    printf("i=%d:[%x] ",i,&i);
    printf("\_\_\_\_\_\_\_\_\_\__ ");
    printf("l:%x ",&l);
    printf("g:%x ",&g);
}

看看k->i的地址的增加順序和l->g的順序是否相同,若是相同則是從右到左,不然從左到右.

PS
原本經過打印參數的值來判斷那個先入棧,結果被一個朋友批評了,
他說:壓棧順序和參數計算順序不是一回事,因此仍是看地址更有保證.

看過的朋友看成笑談吧。
曾經看到一篇文章上面說:c/c++參數壓棧順序是從右到左,pascal參數壓棧是從左到右.

注意點

  1. 儘可能不要在函數參數中運行象pop之類的參數
  2. 32bit和64bit同一源碼時要注意
相關文章
相關標籤/搜索