<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      C語言的變長參數

      C語言的變長參數原理

       

      引言: 在看《程序員的自我修養:第十一章運行庫-11.2.2C語言標準庫》時講到C語言的變長參數以及cdecl,

      所以搜集一些資料幫助理解。

       

      X86調用約定- 維基百科,自由的百科全書

      https://zh.wikipedia.org ? zh-hans

       cdeclstdcall的區別- 簡書

      https://www.jianshu.com ? ...

      關于調用約定(cdeclfastcallstcallthiscall) 的一點知識- ...

      https://www.laruence.com ? 2008/.../...

       c語言如何判斷一個聲明到底是函數還是指針還是數組 ... - 知乎

      https://www.zhihu.com ? question

      https://cdecl.org/

       

      變長參數函數:

      Int printf(const char* format, …);

      cdecl:

      一種X86的調用約定,和語言沒有關系。變長參數實現的基礎是cdecl

      cdecl(C declaration,即C聲明)是源起C語言的一種調用約定,也是C語言的事實上的標準。在x86架構上,其內容包括:

      1. 函數實參在線程棧上按照從右至左的順序依次壓棧。
      2. 函數結果保存在寄存器EAX/AX/AL中
      3. 浮點型結果存放在寄存器ST0中
      4. 編譯后的函數名前綴以一個下劃線字符
      5. 調用者負責從線程棧中彈出實參(即清棧)
      6. 8比特或者16比特長的整形實參提升為32比特長。
      7. 受到函數調用影響的寄存器(volatile registers):EAX, ECX, EDX, ST0 - ST7, ES, GS
      8. 不受函數調用影響的寄存器: EBX, EBP, ESP, EDI, ESI, CS, DS
      9. RET指令從函數被調用者返回到調用者(實質上是讀取寄存器EBP所指的線程棧之處保存的函數返回地址并加載到IP寄存器)

      事實上C++語言默認也是cdecl, 下面的匯編可以清晰的看到調用者完成了清理棧操作

       

       

      補充stdcall

      stdcall是由微軟創建的調用約定,是Windows API的標準調用約定。非微軟的編譯器并不總是支持該調用協議。GCC編譯器如下使用:

      int __attribute__((__stdcall__ )) func()

      stdcall是Pascal調用約定與cdecl調用約定的折衷:被調用者負責清理線程棧,參數從右往左入棧。其他各方面基本與cdecl相同。但是編譯后的函數名后綴以符號"@",后跟傳遞的函數參數所占的棧空間的字節長度。寄存器EAX, ECX和EDX被指定在函數中使用,返回值放置在EAX中。stdcall對于微軟Win32 API和Open Watcom C++是標準。

      微軟的編譯工具規定:PASCAL, WINAPI, APIENTRY, FORTRAN, CALLBACK, STDCALL, __far __pascal, __fortran, __stdcall均是指此種調用約定。

      也就是說調用windows api的代碼的匯編,調用者不清理參數棧,由api函數的匯編代碼清理棧。

       

      變長參數部分待補充


      uint8_t spdlogInit(const char *section);

      void logerror(const char *__restrict fmt, ...);

      #define SPDLOGC_ERROR(fmt, ...) logerror(fmt, ##__VA_ARGS__)

       

      uint8_t spdlogInit(const char *section)
      {
        return util::spdlogInit(section);
      }

      void logerror(const char *__restrict fmt, ...)
      {
        va_list args;
        va_start(args, fmt);
        char s[1024];
        vsnprintf(s, 1024, fmt, args);
        SPDLOG_ERROR(s);
        va_end(args);
      }

      有意思的技巧:

      來源:https://www.zhihu.com/question/439224121

      Int *foo[3]

      看見[N] 讀作 an array of N

      看見()    讀作 a function that returns

      看見T*   讀作 a point to T

      然后從變量開始,先讀右邊的東西,再讀左邊的東西,然后被括號包裹著的話,就跳出去重復這個動作。

      比如int *foo[3]

      An array of 3 points to int

       

      posted @ 2021-04-19 09:52  water_bear  閱讀(526)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久精品午夜视频| 国产一区二区三区18禁| 国产精品国产三级国快看| 91亚洲国产成人久久蜜臀| 欧美 日韩 国产 成人 在线观看| 亚洲香蕉免费有线视频| 国产成人一区二区三区视频免费| 九九热精品在线观看| 国产性三级高清在线观看| 久久精品国产99久久6| 国产成人欧美日韩在线电影| 暖暖影院日本高清...免费| 欧美成本人视频免费播放| 四虎永久在线精品8848a| 日韩高清亚洲日韩精品一区二区| 亚洲欧美精品在线| 午夜福利免费视频一区二区| 国产a在亚洲线播放| 亚洲中文精品一区二区| 无码综合天天久久综合网| 亚洲欧美一区二区成人片| 精品尤物TV福利院在线网站| 欧美日韩在线视频| 玩弄放荡人妻少妇系列| 激情动态图亚洲区域激情| 亚洲av综合色区无码专区| 日韩av片无码一区二区不卡| 色欲AV无码一区二区人妻| 永久免费无码av在线网站| 久久综合九色综合欧洲98| 丹寨县| 特黄做受又粗又大又硬老头| 国产九九视频一区二区三区| 亚洲AV无码国产永久播放蜜芽| 亚洲精品国产男人的天堂| 久久天天躁夜夜躁狠狠| 久久久久久久久久久免费精品| 日韩丝袜亚洲国产欧美一区| 神马久久亚洲一区 二区| 中文字幕一区二区三区久久蜜桃| 亚洲精品国偷自产在线99人热|