<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          c/c++參數(shù)入棧順序和參數(shù)計(jì)算順序

          共 2819字,需瀏覽 6分鐘

           ·

          2021-06-23 21:52

          關(guān)注、星標(biāo)公眾號(hào),直達(dá)精彩內(nèi)容

          ID:技術(shù)讓夢(mèng)想更偉大

          作者:李肖遙


          如果大家細(xì)心的話應(yīng)該知道c/c++語(yǔ)言函數(shù)參數(shù)入棧順序?yàn)閺挠抑磷?,那么為什么這樣呢?來(lái)看看兩個(gè)知識(shí)點(diǎn):參數(shù)的計(jì)算順序與壓棧順序。

          參數(shù)入棧順序

          c/c++中規(guī)定了函數(shù)參數(shù)的壓棧順序是從右至左,函數(shù)調(diào)用協(xié)議會(huì)影響函數(shù)參數(shù)的入棧方式、棧內(nèi)數(shù)據(jù)的清除方式、編譯器函數(shù)名的修飾規(guī)則等。

          參數(shù)傳遞和命名約定

          Visual C/C++ 編譯器支持以下調(diào)用約定。

          關(guān)鍵字堆棧清理參數(shù)傳遞
          __cdeclCaller以相反的順序(從右到左)將參數(shù)壓入堆棧
          __clrcalln/a按順序(從左到右)將參數(shù)加載到 CLR 表達(dá)式堆棧
          __stdcallCallee以相反的順序(從右到左)將參數(shù)壓入堆棧
          __fastcallCallee存儲(chǔ)在寄存器中,然后壓入堆棧
          __thiscallCallee壓入堆棧;此指針存儲(chǔ)在 ECX 中
          __vectorcallCallee存儲(chǔ)在寄存器中,然后以相反的順序(從右到左)壓入堆棧

          官方詳解可見(jiàn):

          https://msdn.microsoft.com/en-us/library/984x0h58(v=vs.120).aspx

          通常情況下c/c++默認(rèn)入棧方式:__cdel,也就是以右到左將參數(shù)壓入堆棧,Windows api使用的是__stdcall方式,__fastcall適用于對(duì)性能要求較高的場(chǎng)合。

          自定義參數(shù)入棧形式

          當(dāng)然我們也可以自定義函數(shù)的入棧順序,常用形式如下

          //函數(shù)返回值  入棧規(guī)則  函數(shù)名(參數(shù)類(lèi)型 參數(shù)名);
          int __cdecl get_name_index(const std::string& str_name);

          為什么要從右往左入棧?

          每個(gè)參數(shù)都有自己的地址,但不定長(zhǎng)參數(shù)無(wú)法確認(rèn)地址,并且函數(shù)參數(shù)的個(gè)數(shù)也不確定,C/C++中規(guī)定了函數(shù)參數(shù)的壓棧順序是從右至左,對(duì)于含有不定參數(shù)的printf函數(shù),其原型是printf(const char* format,…);其中format確定了printf的參數(shù)(通過(guò)format的%個(gè)數(shù)判斷)。

          假設(shè)是從左至右壓棧,那么先入棧的是format,然后依次入棧未知參數(shù),此時(shí)想要知道參數(shù)個(gè)數(shù),就必須找到format,而要找到format,就必須知道參數(shù)個(gè)數(shù),這樣就會(huì)陷入一個(gè)死胡同里面了。

          而c/c++中規(guī)定參數(shù)壓棧為從右至左的順序,這種方式對(duì)于不定參數(shù),最后入棧的是參數(shù)個(gè)數(shù),只需要取棧頂就可以得到。

          我們舉一個(gè)了例子如下:

          //win10+vs2019
          //來(lái)源:技術(shù)讓夢(mèng)想更偉大
          //作者:李肖遙
          #include <iostream>
          using namespace std;

          void fun(int x, int y, int z)
          {
              cout << x << &x << endl;
              cout << y << &y << endl;
              cout << z << &z << endl;
          }

          int main(int argc, char *argv[])
          {
              fun(1, 2, 3);
              system("pause");
              return 0;
          }

          輸出結(jié)果如下:

          我們知道先入棧的占高地址,從結(jié)果看出入棧的順序依次為z->y->x,即壓棧順序從右至左。

          參數(shù)計(jì)算順序

          先執(zhí)行哪個(gè)參數(shù)和參數(shù)的計(jì)算順序有關(guān),而c/c++中沒(méi)有規(guī)定函數(shù)參數(shù)的計(jì)算順序,這個(gè)和編譯器有關(guān),代碼參數(shù)的計(jì)算順序決定了實(shí)際輸出。

          //來(lái)源:技術(shù)讓夢(mèng)想更偉大
          //作者:李肖遙
          #include <stdio.h>

          int main () {
           int a = 2;
           printf("%d, %d, %d", a, (a = (a + 2)), (a = (a + 3)));
           system("pause");
           return 0;
          }
          //win10 + VS2019 輸出: 7, 7, 7
          //clang輸出結(jié)果 2 4 7 

          vs的計(jì)算順序是從右至左,clang的計(jì)算順序是從左至右,具體的計(jì)算流程分析就很簡(jiǎn)單了。

          對(duì)于c/c++函數(shù)參數(shù)的讀取順序,參數(shù)入棧時(shí)順序從右向左入棧,但是在入棧前會(huì)先把參數(shù)列表里的表達(dá)式從右向左算一遍得到表達(dá)式的結(jié)果,最后再把這些運(yùn)算結(jié)果統(tǒng)一入棧。

          在參數(shù)入棧前,編譯器會(huì)先把參數(shù)的表達(dá)式都處理掉,對(duì)于一般的操作來(lái)說(shuō),參數(shù)入棧時(shí)取值是直接從變量的內(nèi)存地址里取的,但是對(duì)于a++操作,編譯器會(huì)開(kāi)辟一個(gè)緩沖區(qū)來(lái)保存當(dāng)前a的值,然后再對(duì)a繼續(xù)操作,最后參數(shù)入棧時(shí)的取值是從緩沖區(qū)取,而不是直接從a的內(nèi)存地址里取。

          結(jié)論

          因?yàn)楹瘮?shù)參數(shù)的計(jì)算順序依照編譯器的實(shí)現(xiàn),所以在編碼中避免編寫(xiě)諸如 fun(++x, x+y)這種的程序,其在不同的平臺(tái)得到的結(jié)果可能不一樣,但是在面試中可能遇到這樣的問(wèn)題,所以我們需要知其然更要知所以然。

          ????????????????  END  ????????????????

          推薦閱讀:


          嵌入式編程專(zhuān)輯
          Linux 學(xué)習(xí)專(zhuān)輯
          C/C++編程專(zhuān)輯
          Qt進(jìn)階學(xué)習(xí)專(zhuān)輯

          關(guān)注我的微信公眾號(hào),回復(fù)“加群”按規(guī)則加入技術(shù)交流群。


          點(diǎn)擊“閱讀原文”查看更多分享。

          瀏覽 114
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人精品A | 日本一区二区电影久久精品 | 天天草天天日天天干 | 精品艹逼| 五月丁香之婷婷 |