1. 程式人生 > >函式呼叫約定與函式名稱修飾規則(一)

函式呼叫約定與函式名稱修飾規則(一)

    作者:星軌(oRbIt)
    E_Mail:
[email protected]
    轉載請註明原作者,否則請勿轉載

      使用C/C++語言開發軟體的程式設計師經常碰到這樣的問題:有時候是程式編譯沒有問題,但是連結的時候總是報告函式不存在(經典的LNK 2001錯誤),有時候是程式編譯和連結都沒有錯誤,但是隻要呼叫庫中的函式就會出現堆疊異常。這些現象通常是出現在C和C++的程式碼混合使用的情況下或在C++程式中使用第三方的庫的情況下(不是用C++語言開發的),其實這都是函式呼叫約定(Calling Convention)和函式名修飾(Decorated Name)規則惹的禍。函式呼叫方式決定了函式引數入棧的順序,是由呼叫者函式還是被呼叫函式負責清除棧中的引數等問題,而函式名修飾規則決定了編譯器使用何種名字修飾方式來區分不同的函式,如果函式之間的呼叫約定不匹配或者名字修飾不匹配就會產生以上的問題。本文分別對C和C++這兩種程式語言的函式呼叫約定和函式名修飾規則進行詳細的解釋,比較了它們的異同之處,並舉例說明了以上問題出現的原因。

函式呼叫約定(Calling Convention)

    函式呼叫約定不僅決定了發生函式呼叫時函式引數的入棧順序,還決定了是由呼叫者函式還是被呼叫函式負責清除棧中的引數,還原堆疊。函式呼叫約定有很多方式,除了常見的__cdecl,__fastcall和__stdcall之外,C++的編譯器還支援thiscall方式,不少C/C++編譯器還支援naked call方式。這麼多函式呼叫約定常常令許多程式設計師很迷惑,到底它們是怎麼回事,都是在什麼情況下使用呢?下面就分別介紹這幾種函式呼叫約定。


1.__cdecl

    編譯器的命令列引數是/Gd。__cdecl方式是C/C++編譯器預設的函式呼叫約定,所有非C++成員函式和那些沒有用__stdcall或__fastcall宣告的函式都預設是__cdecl方式,它使用C函式呼叫方式,函式引數按照從右向左的順序入棧,函式呼叫者負責清除棧中的引數,由於每次函式呼叫都要由編譯器產生清除(還原)堆疊的程式碼,所以使用__cdecl方式編譯的程式比使用__stdcall方式編譯的程式要大很多,但是__cdecl呼叫方式是由函式呼叫者負責清除棧中的函式引數,所以這種方式支援可變引數,比如printf和windows的API wsprintf就是__cdecl呼叫方式。對於C函式,__cdecl方式的名字修飾約定是在函式名稱前新增一個下劃線;對於C++函式,除非特別使用extern "C",C++函式使用不同的名字修飾方式。


2.__fastcall

    編譯器的命令列引數是/Gr。__fastcall函式呼叫約定在可能的情況下使用暫存器傳遞引數,通常是前兩個 DWORD型別的引數或較小的引數使用ECX和EDX暫存器傳遞,其餘引數按照從右向左的順序入棧,被呼叫函式在返回之前負責清除棧中的引數。編譯器使用兩個@修飾函式名字,後跟十進位制數表示的函式引數列表大小,例如:@[email protected]。需要注意的是__fastcall函式呼叫約定在不同的編譯器上可能有不同的實現,比如16位的編譯器和32位的編譯器,另外,在使用內嵌彙編程式碼時,還要注意不能和編譯器使用的暫存器有衝突。


3.__stdcall
 
    編譯器的命令列引數是/Gz,__stdcall是Pascal程式的預設呼叫方式,大多數Windows的API也是__stdcall呼叫約定。__stdcall函式呼叫約定將函式引數從右向左入棧,除非使用指標或引用型別的引數,所有引數採用傳值方式傳遞,由被呼叫函式負責清除棧中的引數。對於C函式,__stdcall的名稱修飾方式是在函式名字前新增下劃線,在函式名字後新增@和函式引數的大小,例如:

[email protected]

4.thiscall

    thiscall只用在C++成員函式的呼叫,函式引數按照從右向左的順序入棧,類例項的this指標通過ECX暫存器傳遞。需要注意的是thiscall不是C++的關鍵字,不能使用thiscall宣告函式,它只能由編譯器使用。

5.naked call

    採用前面幾種函式呼叫約定的函式,編譯器會在必要的時候自動在函式開始新增儲存ESI,EDI,EBX,EBP暫存器的程式碼,在退出函式時恢復這些暫存器的內容,使用naked call方式宣告的函式不會新增這樣的程式碼,這也就是為什麼稱其為naked的原因吧。naked  call不是型別修飾符,故必須和_declspec共同使用。

    VC的編譯環境預設是使用__cdecl呼叫約定,也可以在編譯環境的Project Setting...選單-》C/C++ =》Code  Generation項選擇設定函式呼叫約定。也可以直接在函式宣告前新增關鍵字__stdcall、__cdecl或__fastcall等單獨確定函式的呼叫方式。在Windows系統上開發軟體常用到WINAPI巨集,它可以根據編譯設定翻譯成適當的函式呼叫約定,在WIN32中,它被定義為__stdcall。   

(未完)

相關推薦

函式呼叫約定函式名稱修飾規則

    作者:星軌(oRbIt)    E_Mail:[email protected]    轉載請註明原作者,否則請勿轉載       使用C/C++語言開發軟體的程式設計師經常碰到這樣的問題:有時候是程式編譯沒有問題,但是連結的時候總是報告函式不存在(經典的L

函式呼叫約定函式修飾規則

函式呼叫約定:是指當一個函式被呼叫時,函式的引數會被傳遞給被呼叫的函式和返回值會被返回給呼叫函式。函式的呼叫約定就是描述引數是怎麼傳遞和由誰平衡堆疊的,當然還有返回值。 幾種型別:__stdcall,__cdecl,__fastcall,__thiscall,__n

Python修飾—— 函式修飾符 “@”

Python函式修飾符,“@”,與其說是修飾函式倒不如說是引用、呼叫它修飾的函式。 舉個栗子,下面的一段程式碼,裡面兩個函式,沒有被呼叫,也會有輸出結果: def test(f):     print "before ..."     f()     print "aft

深度學習筆記——理論推導之概念,成本函式梯度下降演算法初識

前情提要 一、神經網路介紹 概念:Learning ≈ Looking for a Function 框架(Framework): What is Deep Learning? 深度學習其實就是一個定義方法、判斷方法優劣、挑選最佳的方法的過程:

ORACLE inexists語句的區別

表數 內存 全部 sel 一個 性能 where 情況 lec (轉載:https://www.cnblogs.com/iceword/archive/2011/02/15/1955337.html) select * from Awhere id in(select id

數據結構算法小結——排序

思路 基礎上 bubuko 時間復雜度 inf pla 都是 tex .com   前段時間Java學了,數據結構與算法看了,機器學習也了解了一點,還裝上Ubuntu了解了Linux。接受的東西太多太雜,需要梳理一下。   首先是最重要的數據結構和算法,無論以後搞什麽,只要

React-Native系列Android——NativeJavascript通信原理

from 直接 最新 一點 明顯 rem 負責 receive esp React-Native最核心的是Native與Javascript之間的通信,並且是雙向通信

python 條件語句數據類型

info 分享 基本語句 額外 -a 縮進 == inpu pass   例:   如果 1=1,那麽就會輸出 "hello world" 否則 輸出 "hello penphy" 代碼塊: 1 if 條件 : 2   print("hello wor

《黑客畫家》讀書筆記

能說 互聯 可能 研究 歷史 設計 職位 天下無敵 聯網 《黑客與畫家》讀書筆記(一) 黑客與畫家 黑客與畫家的共同之處,在於他們都是創作者,都試圖創作出優秀的作品。 他們本質上都不是在做研究,雖然過程中可能發現一些新技術。黑客的出發點是原創,最終得到一個優美的結果;科學家

從Paxos到Zookeeper分散式一致性原理實踐 讀書筆記之 分散式架構

1.1 從集中式到分散式  1 集中式特點  結構簡單,無需考慮對多個節點的部署和節點之間的協作。  2  分散式特點 分不性:在時間可空間上隨意分佈,機器的分佈情況隨時變動 對等性:計算機之間沒有主從之分,所有計算機之間是對等的。副本是分散式系統對資料

RxDataSourcesTableView實現介面展示

// ViewController.swift // RxSwiftTest // // Created by travey on 2018/11/5. // Copyright © 2018年 ZhouShijie. All rights reserved. import UIKit

Linux命令列shell指令碼程式設計大全

一、基本 bash shell命令 建立檔案 : touch 連結檔案:符號連結:是一個實實在在的檔案,兩個通過符號連結在一起的檔案,彼此的內容並不相同。使用ln -s命令。 硬連結:會建立獨立的虛擬檔案,其中包含了原始檔案的資訊及位置。但他們從根本上而言是同一個檔案。原始檔案必須事

C#中委託事件的學習小結

最近又學習了一些C#的小知識點,在此釋出部落格記錄一下。 一、委託 C#中的委託的關鍵字是delegate,我們可以使用委託型別來將已有的方法例項化出來,也可以將我們自己定義的方法作為引數來傳遞。 例如: private delegate string GetAStri

HTMLCSS的一些知識

  一般寫程式碼的時候,總會有些小錯誤。為了便於修改以及查詢,所以程式碼格式要寫規範,而且一定一定要寫註釋。因為有時候程式碼寫得多了,真的連自己都找不到自己要找的東西在哪裡。還有命名也要見名知意。   再說一些HTML相關:   1、標籤分類:        a、塊級標籤:<div><

Qt之遊戲手柄的互動

用途 通過手柄與Qt的通訊,傳送指令至遠端裝置,控制遠端裝置的運動。 手柄種類 市面上的遊戲手柄也有多種種類,主流的是藍芽手柄、2.4g手柄和usb手柄。2.4g手柄有的會識別出來是Xbox裝置,有的識

【機器學習】資料探勘演算法——關聯規則,相關概念,評價指標

綜述:        資料探勘是指以某種方式分析資料來源,從中發現一些潛在的有用的資訊,所以資料探勘又稱作知識發現,而關聯規則挖掘則是資料探勘中的一個很重要的課題,顧名思義,它是從資料背後發現事物之間可能存在的關聯或者聯絡。 關聯規則的目的在於在一個數據集中找出項之間的關

演算法設計分析——二叉堆

本blog主要介紹了二叉堆、二項式堆,下一篇部落格將介紹斐波拉契堆。 二叉堆和二項式堆、斐波拉契堆都是用於實現優先佇列的高階資料結構,以不同堆實現的優先佇列會有不同的時間複雜度。 問題引入 在實際應用中,我們經常會遇到在最多由n個數組成的動態集合SSS上得到這個

編譯程式碼安全之認識

         好久沒有更新部落格了,今天週末索性喝杯茶,靜下心來把最近一段時間自己所理解和思考的關於軟體程式碼保護的東西寫下來。幫助所需之人,多有不對,望批評指正。         一提到編譯,大家很多人覺得不就是詞法分析、語法分析然後產生一個針對特定機器的檔案。感覺這

android java native互動 基礎學習

javap 與javah的用法 javap 的用法: cd 到 class 所在的目錄: javap -classpath . -s Bean(類名) java h的用法一: native 所在的資料夾。ExampleUnitTest 資料夾所在的包

vue json-server 新增資料

列表頁server.vue <!-- 按鈕 --> <div class="tj"> <span class="demonstration">ID</span> <el-input class="int-1" v-mode