• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            xiaoguozi's Blog
            Pay it forword - 我并不覺的自豪,我所嘗試的事情都失敗了······習慣原本生活的人不容易改變,就算現狀很糟,他們也很難改變,在過程中,他們還是放棄了······他們一放棄,大家就都是輸家······讓愛傳出去,很困難,也無法預料,人們需要更細心的觀察別人,要隨時注意才能保護別人,因為他們未必知道自己要什么·····

             

            左通過棧傳遞,被調用的函數在返回前清理傳送參數的內存棧,但不同的 是函數名的修飾部分(關于函數名的修飾部分在后面將詳細說明)。

            _stdcall
            Pascal程序的缺省調用方式,通常用于Win32 Api中,函數采用從右到左 的壓棧方式,自己在退出時清空堆棧。VC將函數編譯后會在函數名前面加上下劃線前綴,在函數名后加上"@"和參數的字節數。


            2
            C調 用約定(即用__cdecl關鍵字說明)按從右至左的順序壓參數入棧,由調用者把參數彈出棧。對于傳送參數的內存棧是由調用者來維護的(正因為如此,實現可變參數的函數只 能使用該調用約定)。另外,在函數名修飾約定方面也有所不同。


            _cdecl
            CC++程序的缺省調用方式。每一個調用它的函數都包含清空堆棧的代碼,所 以產生的可執行文件大小會比調用_stdcall函數的大。函數采用從右到左的壓棧方式。VC將函數編譯后會在函數名前面加上下劃線前綴。是MFC缺省調用約定。


            3
            __fastcall調用約定是“人”如其名,它的主要特點就是快,因為它是通過寄存器來傳送參數的(實際上,它用ECXEDX傳送前兩個雙字(DWORD)或更小的參數,剩下的參數仍舊自右向左壓棧傳送,被調用的函數在返 回前清理傳送參數的內存棧),在函數名修飾約定方面,它和前兩者均不同。


            _fastcall
            方式的函數采用寄存器傳遞參數,VC將函數編譯后會在函數名前面加上"@"前綴,在函數名后加上"@"和參數的字節數。


            4
            thiscall僅僅應用于“C++”成員函數。this指針存放于CX寄存器,參數從右到左壓。thiscall不是關鍵詞,因此不能被程序員指定。


            5
            naked call采用1-4的調用約定時,如果必要的話,進入函數時編譯器會產生代碼來保存ESIEDIEBXEBP寄存器,退出函數時則產生代碼恢復這些寄存器的內容。naked call不產生這樣的代碼。naked call不是類型修飾符,故 必須和_declspec共同使用。


            關鍵字 __stdcall__cdecl__fastcall可以直接加在要輸出的函數前,也可以在編譯環境的Setting...\C/C++ \Code Generation項選擇。當加在輸出函數前的關鍵字與編譯環境中的選擇不同時,直接加在輸出函數前的關鍵字有效。它們對應的命令行參數分別為/Gz/Gd/Gr。缺省狀態為/Gd,即__cdecl


            要完全模仿PASCAL調用約定首先必須使用__stdcall調用約定,至于函數名修飾約定,可以通過其它方法模仿。還有一個值得 一提的是WINAPI宏,Windows.h支持該宏,它可以將出函數翻譯成適當的調用約定,在WIN32中,它被定義為__stdcall。使用WINAPI宏可以創建自己的APIs


            2)
            名字修飾約定


            1
            、修飾名
            (Decoration name)

            C”或者“C++”函數在內部(編譯和鏈接)通過修飾名識別。修飾名是編譯器在編譯函 數定義或者原型時生成的字符串。有些情況下使用函數的修飾名是必要的,如在模塊定義文件里頭指定輸出“C++”重載函數、構造函數、析構函數,又如在匯編代碼里調用“C””或“C++”函數等。


            修飾名由函數名、類名、調用約定、返回類型、參數等共同決定。


            2
            、名字修飾約定隨調用約定和編譯種類(CC++)的不同而變化。函數名修飾約定隨編譯種類和調用約定的不同而不同,下 面分別說明。


            a
            C編譯時函數名修飾約定規則:


            __stdcall
            調用約定在輸出函數名前加上一個下劃線前綴,后面加上一個“@”符號和其參數的字節數,格式為_functionname@number


            __cdecl
            調用約定僅在輸出函數名前加上一個下劃線前綴,格式為_functionname


            __fastcall
            調用約定在輸出函數名前加上一個“@”符號,后面也是一個“@”符號和其參數的字節數,格式為@functionname@number


            它們均不改變輸出函數名中的字符大小寫,這和PASCAL調用約定不同,PASCAL約定輸出的函數名無任何修飾且全部大寫。


            b
            C++編 譯時函數名修飾約定規則:


            __stdcall
            調用約定:

            1
            、 以“?”標識函數 名的開始,后跟函數名;

            2
            、函數名后面以“@@YG”標識參數表的開始,后跟參數表;

            3
            、 參數表以代號表示:

            X--void

            D--char

            E--unsigned char

            F--short

            H--int

            I--unsigned int

            J--long

            K--unsigned long

            M--float

            N--double

            _N--bool

            ....
            PA--
            表示指 針,后面的代號表明指針類型,如果相同類型的指針連續出現,以“0”代替,一個“0”代表一次重復;

            4
            、 參數表的第一項為該函數的返回值類型,其后依次為參數的數據類型,指針標識在其所指數據類型前;

            5
            、 參數表后以“@Z” 標識整個名字的結束,如果該函數無參數,則以“Z”標識結束。


            其格式為“?functionname@@YG*****@Z”或“?functionname@@YG*XZ”,例如

            int Test1
            char *var1,unsigned long-----?Test1@@YGHPADK@Z

            void Test2
            () -----?Test2@@YGXXZ


            __cdecl
            調用約定:

            規 則同上面的_stdcall調用約定,只是參數表的開始標識由上面的“@@YG”變為“@@YA”。


            __fastcall
            調用約定:

            規 則同上面的_stdcall調用約定,只是參數表的開始標識由上面的“@@YG”變為“@@YI”。


            VC++
            對函數的省缺聲明是"__cedcl",將只能被C/C++調用
            .

            CB
            在輸出函數聲明時使用4種修飾符號

            //__cdecl
            cb
            的默認值,它會在輸出函數名前加_,并保留此函數名不變,參數按照從右到左的順序依次傳遞給棧,也可以寫 成_cdeclcdecl形式。

            //__fastcall
            她修飾的函數的參 數將盡肯呢感地使用寄存器來處理,其函數名前加@,參數按照從左到右的順序壓棧;

            //__pascal
            它說明的函數名使 用Pascal格 式的命名約定。這時函數名全部大寫。參數按照從左到右的順序壓棧;

            //__stdcall
            使用標準約定的函 數名。函數名不會改變。使用__stdcall修飾時。參數按照由右到左的順序壓棧,也可以是_stdcall


            TITLE  : __stdcall與__cdecl的區別
            AUTHOR : lionel@nkbbs.org
            DATE   : 
            01/10/2005

            CONTENT:

                Visual C
            ++ Compiler Options可以指定的Calling Convention有 3種:
               
                
            /Gd /Gr /Gz
               
                這三個參數決定了:
               
                
            1.函數參數以何種順序入棧,右到左還是左到右。
                
            2.在函數運行完后,是調用函數還是被調用函數清理入棧的參數。
                
            3.在編譯時函數名字是如何轉換的。
               
                下面我們分別詳細介紹:
               
                
            1./Gd
                    這是編譯器默認的轉換模式,對一般函數使用 C的函數調用轉換方式__cdecl,
                    但是對于C
            ++ 成員函數和前面修飾了__stdcall __fastcall的函數除外。
                   
                
            2./Gr
                    對于一般函數使用__fastcall函數調用轉換方式,所有使用__fastcall的函數
                    必須要有函數原形。但對于C
            ++ 成員函數和前面修飾了__cdecl __stdcall 的
                    函數除外。
                   
                
            3./Gz
                    對于所有 C函數使用__stdcall函數調用轉換方式,但對于可變參數的 C函數以
                    及用__cdecl __fastcall修飾過的函數和C
            ++ 成員函數除外。所有用__stdcall
                    修飾的函數必須有函數原形。
                   
                    事實上,對于x86系統,C
            ++ 成員函數的調用方式有點特別,將成員函數的this
                    指針放入ECX,所有函數參數從右向左入棧,被調用的成員函數負責清理入棧的
                    參數。對于可變參數的成員函數,始終使用__cdecl的轉換方式。
                   
                下面該進入主題,分別講一下這三種函數調用轉換方式有什么區別:
               
                
            1.__cdecl
                    這是編譯器默認的函數調用轉換方式,它可以處理可變參數的函數調用。參數
                    的入棧順序是從右向左。在函數運行結束后,由調用函數負責清理入棧的參數。
                    在編譯時,在每個函數前面加上下劃線(_),沒有函數名大小寫的轉換。即
                   
                      _functionname
                   
                
            2.__fastcall
                    有一些函數調用的參數被放入ECX,EDX中,而其它參數從右向左入棧。被調用
                    函數在它將要返回時負責清理入棧的參數。在內嵌匯編語言的時候,需要注意
                    寄存器的使用,以免與編譯器使用的產生沖突。函數名字的轉換是:
                   
                      @functionname@number
                   
                    沒有函數名大小寫的轉換,number表示函數參數的字節數。由于有一些參數不
                    需要入棧,所以這種轉換方式會在一定程度上提高函數調用的速度。
                   
                
            3.__stdcall
                  函數參數從右向左入棧,被調用函數負責入棧參數的清理工作。函數名轉換格
                  式如下:
               
                    _functionname@number
               
                下面我們親自寫一個程序,看看各種不同的調用在編譯后有什么區別,我們的被調
                用函數如下:
               
                
            int function(int a, int b)
                {
                    
            return a + b;
                }
               
                
            void main()
                {
                    function(
            1020);
                }
               
                
            1.__cdecl
                   
                    _function

                             push    ebp
                             mov     ebp, esp
                             mov     eax, [ebp
            +8]       ;參數1
                             add     eax, [ebp
            +C]       ;加上參數2
                             pop     ebp
                             retn

                    _main
                             push    ebp
                             mov     ebp, esp
                             push    14h                ;參數 2入棧
                             push    0Ah                ;參數 1入棧
                             call    _function          ;調用函數
                             add     esp, 
            8             ;修正棧
                             xor     eax, eax
                             pop     ebp
                             retn
                            
                
            2.__fastcall
               
                    @function@
            8
                             push    ebp
                             mov     ebp, esp           ;保存棧指針
                             sub     esp, 
            8             ;多了兩個局部變量
                             mov     [ebp
            -8], edx       ;保存參數 2
                             mov     [ebp
            -4], ecx       ;保存參數 1
                             mov     eax, [ebp
            -4]       ;參數 1
                             add     eax, [ebp
            -8]       ;加上參數 2
                             mov     esp, ebp           ;修正棧
                             pop     ebp
                             retn

                    _main
                             push    ebp
                             mov     ebp, esp
                             mov     edx, 14h           ;參數 2給EDX
                             mov     ecx, 0Ah           ;參數 1給ECX
                             call    @function@
            8        ;調用函數
                             xor     eax, eax
                             pop     ebp
                             retn
             
                
            3.__stdcall
               
                    _function@
            8

                             push    ebp
                             mov     ebp, esp
                             mov     eax, [ebp]         ;參數 
            1
                             add     eax, [ebp
            +C]       ;加上參數 2
                             pop     ebp
                             retn    
            8                  ;修復棧

                    _main
                             push    ebp
                             mov     ebp, esp
                             push    14h                ;參數 2入棧
                             push    0Ah                ;參數 1入棧 
                             call    _function@
            8    ;函數調用
                             xor     eax, eax
                             pop     ebp
                             retn

                可見上述三種方法各有各的特點,而且_main必須是__cdecl,一般WIN32的函數都是
                __stdcall。而且在Windef.h中有如下的定義:
               
                
            #define CALLBACK __stdcall
                
            #define WINAPI  __stdcall

            posted on 2010-07-01 09:27 小果子 閱讀(270) 評論(0)  編輯 收藏 引用 所屬分類: 學習筆記
            精品久久久久久无码中文字幕 | 一本久久综合亚洲鲁鲁五月天亚洲欧美一区二区 | 国产精品毛片久久久久久久 | 国产精品久久久久无码av| 久久99国产精品久久99| 欧洲性大片xxxxx久久久| 伊人久久精品无码二区麻豆| 久久精品这里热有精品| 亚洲精品国产第一综合99久久| 性做久久久久久久| 久久综合视频网站| 国产精品久久久久久一区二区三区| 久久精品人妻一区二区三区| 人妻精品久久久久中文字幕一冢本| 国产亚州精品女人久久久久久 | 色99久久久久高潮综合影院 | 品成人欧美大片久久国产欧美| 中文精品99久久国产| 成人综合伊人五月婷久久| 伊人色综合久久天天网| 91久久九九无码成人网站| 麻豆av久久av盛宴av| 久久久久久毛片免费看| 久久国产精品国产自线拍免费| 久久久久久精品免费免费自慰| 久久影院午夜理论片无码| 日本免费一区二区久久人人澡| 久久国产色AV免费看| 一本色道久久88精品综合| 无码国内精品久久人妻麻豆按摩 | 久久精品无码专区免费| 久久精品国产99国产电影网| 老色鬼久久亚洲AV综合| 伊人久久大香线蕉综合影院首页 | 囯产极品美女高潮无套久久久| 免费精品久久久久久中文字幕| 久久国产热这里只有精品| 久久精品不卡| 思思久久99热只有频精品66| 香蕉久久久久久狠狠色| 久久99精品国产麻豆宅宅|