cdll和windll的差別

2021-09-22 12:05:31 字數 2553 閱讀 6786

python要想呼叫

c語言寫的動態連線庫。不僅要相容

c介面的呼叫習慣,還須要相容

c語言的資料型別。幸運的是

ctypes

庫已經做了這雙方面的工作。以便呼叫動態連線庫是很方便的。在

hello world

的程式裡,這行**編寫例如以下:

messagebox = windll.user32.messageboxw

從這行**的簡潔程度來看。是很優美的。這樣的優美是因為ctypes

庫在背後做了許多的工作。比方

windll

事實上是乙個比較複雜的物件。在

ctypes

庫里,它提供了三個easy載入動態連線庫的物件:

cdll

、windll

和oledll

。通過訪問這三個物件的屬性,就能夠呼叫動態連線庫的函式了。

當中cdll

主要用來載入

c語言呼叫方式(

cdecl

)。windll

主要用來載入

win32

呼叫方式(

stdcall

),而oledll

使用win32

呼叫方式(

stdcall

)且返回值是

windows

裡返回的

hresult

值。假設你曾經沒有學習過程式設計,肯定沒有辦法區分

cdecl

和stdcall

,就算學習過程式設計,假設沒有寫過跨不同庫之間的呼叫,也未必知道。因為在眼下

ide的開發環境下,已經所有隱藏這些的細節。

但在跨語言方面呼叫時,就不能忽略這樣的細節了。那麼你或許問為什麼會出現這兩種呼叫方式,不是同乙個動態連線庫嗎?對於這個問題。問得好。

要回答這個問題,得從發明c

語言那時候說起。

在70年代。美國人丹尼斯·里奇發明了

c語言。而且使用

c語言編寫

unix

,由此他就成為了

c語言之父和

unix

作業系統之父。因為

unix

作業系統很高效,改動起來也很方便,是得益於使用了

c語言來編寫。

隨著unix

作業系統的推廣,

c語言也變成了乙個流行的語言。

要讓unix

變得高效率。那麼

c語言的設計上,就要著眼於高效的設計。

在函式呼叫這方面的設計,就體現了這一點。在c

語言的函式呼叫時。須要傳送多個引數。

這些引數的傳送是能夠通過暫存器或者棧來傳送。那你或許問為什麼不僅僅使用暫存器這一種方式呢?因為函式呼叫的引數比較多。比方達到5個。

而且在那時候的cpu

的暫存器很少,也滿足不了這個要求。不像眼下

arm或

mips

的cpu

,暫存器比較多。多達

13個之多。這時所有使用暫存器來傳送引數是基本能夠解決這個問題了。在當時的環境之下,設計的

c語言的編譯器都是按棧的方式來傳遞函式呼叫的引數,這樣不但能夠解決暫存器少的問題,也能夠解決另外乙個問題。就是能夠動態地傳遞引數的個數。

上面僅僅是攻克了個數的問題,那又出現了另外乙個問題,就是引數的入棧的順序問題。這個好比像學校裡體育老師叫一班學生來排隊。排頭是從高到矮,還是從矮到高的選擇。在入棧這個問題上。c

語言也面臨兩個選擇。乙個跟**的書寫的順序一樣從左到右,還有乙個是從右到左。在考慮到動態引數的問題之後,

c語言的設計者採用了從右到左的入棧方式,這樣的方式有兩個長處:一是函式執行時,預設方式是從左到右,意味著出棧的方向應優先為棧頂的元素,這樣能夠提高執行效率;二是函式引數不定時,執行時分析字串裡出現須要的引數,每出現乙個引數就彈出棧一次,跟執行分析的順序一致。比方以下的函式宣告:

printf(const char *,...);

由上可見入棧的順序不同,呼叫的方式就不一樣。在c

語言裡都是採用從右向左的方式入棧。在

pascal

語言裡是從左向右入棧順序的。在

ctypes

庫里cdll

、windll

和oledll

都是支援從右到左入棧的引數順序。

接著下來又引出來了另外乙個問題,既然引數是採用入棧的方式來傳遞。那麼就會出現這樣的情況,當棧的引數沒有使用到時,誰來清除。恢復棧的狀態。

在這個問題上。在編譯器的設計者裡又出現了兩種選擇:一種是傾向呼叫者清除。一種是傾向被呼叫者清除。

這兩種方式在效能上沒有什麼差別,僅僅是安排清除的**在不同的位置上。cdll

是使用呼叫者清除的棧的方式。而

windll

和oledll

是使用被呼叫者清除。這點就是它們之間的差別。因此。

python

裡呼叫動態連線庫時。一定要清楚每乙個函式使用的呼叫方式,否則程式就會出問題。重則直接死掉。

cdll

和windll

的差別例如以下圖:

cdll和windll的差別

python要想呼叫 c語言寫的動態連線庫。不僅要相容 c介面的呼叫習慣,還須要相容 c語言的資料型別。幸運的是 ctypes 庫已經做了這雙方面的工作。以便呼叫動態連線庫是很方便的。在 hello world 的程式裡,這行 編寫例如以下 messagebox windll.user32.mess...

ifdef和 if的差別

最近專案要從windows平台移植到linux平台,所以做了很多相容性相關的工作。遇到乙個小問題,我想通過win32巨集來區分兩個平台,之前以外win32變數是自己定義到,所以我做了如下宣告 define win32 1 1 windows,0 linux 程式中這樣使用 if win32 1 do...

引用和指標的差別,陣列和指標的差別

一 引用和指標的差別 1 引用並不是物件,它僅僅是為乙個已存在的物件所起的另外乙個名字。必須初始化,並且無法改變它繫結的物件,之後每次使用這個引用都是訪問最初繫結的那個物件。2 指標本身是物件,能夠不用初始化,能夠改變指標指向的物件 二 指標與陣列的差別 指標陣列 儲存資料的位址 儲存資料 間接訪問...