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 指標本身是物件,能夠不用初始化,能夠改變指標指向的物件 二 指標與陣列的差別 指標陣列 儲存資料的位址 儲存資料 間接訪問...