Python和C++語(yǔ)言的整合

利用 ctypes 模塊整合 Python 程序和 C 程序
ctypes 模塊
ctypes 是 Python 的一個(gè)標(biāo)準(zhǔn)模塊携御,它包含在 Python2.3 及以上的版本里。ctypes 是一個(gè) Python 的高級(jí)外部函數(shù)接口,它使得 Python 程序可以調(diào)用 C 語(yǔ)言編譯的靜態(tài)鏈接庫(kù)和動(dòng)態(tài)鏈接庫(kù)。運(yùn)用 ctypes 模塊玛迄,能夠在 Python 源程序中創(chuàng)建,訪問(wèn)和操作簡(jiǎn)單的或復(fù)雜的 C 語(yǔ)言數(shù)據(jù)類(lèi)型棚亩。最為重要的是 ctypes 模塊能夠在多個(gè)平臺(tái)上工作蓖议,包括 Windows,Windows CE讥蟆,Mac OS X勒虾,Linux,Solaris瘸彤,F(xiàn)reeBSD修然,OpenBSD。
接下來(lái)通過(guò)幾個(gè)簡(jiǎn)單的例子來(lái)看一下 ctypes 模塊如何整合 Python 程序和 C 程序质况。
源代碼層面上的整合
利用 Python 本身提供的 ctypes 模塊可以使 Python 語(yǔ)言和 C 語(yǔ)言在源代碼層面上進(jìn)行整合愕宋。本節(jié)介紹了如何通過(guò)使用 ctypes 庫(kù),在 Python 程序中可以定義類(lèi)似 C 語(yǔ)言的變量结榄。
下表列出了 ctypes 變量類(lèi)型中贝,C 語(yǔ)言變量類(lèi)型和 Python 語(yǔ)言變量類(lèi)型之間的關(guān)系:
表 1. ctypes,c 語(yǔ)言和 Python 語(yǔ)言變量類(lèi)型關(guān)系

表1

表 1 中的第一列是在 ctypes 庫(kù)中定義的變量類(lèi)型臼朗,第二列是 C 語(yǔ)言定義的變量類(lèi)型邻寿,第三列是 Python 語(yǔ)言在不使用 ctypes 時(shí)定義的變量類(lèi)型。
舉例:
清單 1. ctypes 簡(jiǎn)單使用

>>> from ctypes import * # 導(dǎo)入 ctypes 庫(kù)中所有模塊
>>> i = c_int(45) # 定義一個(gè) int 型變量视哑,值為 45 
>>> i.value # 打印變量的值 45 
>>> i.value = 56 # 改變?cè)撟兞康闹禐?56 
>>> i.value # 打印變量的新值 56

從下面的例子可以更明顯地看出 ctypes 里的變量類(lèi)型和 C 語(yǔ)言變量類(lèi)型的相似性:
清單 2. ctypes 使用 C 語(yǔ)言變量

>>> p = create_string_buffer(10) # 定義一個(gè)可變字符串變量绣否,長(zhǎng)度為 10 
>>> p.raw # 初始值是全 0,即 C 語(yǔ)言中的字符串結(jié)束符’ \0 ’'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' 
>>> p.value = "Student" # 字符串賦值 
>>> p.raw # 后三個(gè)字符仍是’ \0 ’'Student\x00\x00\x00' 
>>> p.value = "Big" # 再次賦值 
>>> p.raw # 只有前三個(gè)字符被修改挡毅,第四個(gè)字符被修改為’ \0 ’'Big\x00ent\x00\x00\x00'

下面例子說(shuō)明了指針操作:
清單 3. ctypes 使用 C 語(yǔ)言指針

>>> i = c_int(999) # 定義 int 類(lèi)型變量 i蒜撮,值為 999 
>>> pi = pointer(i) # 定義指針,指向變量 i 
>>> pi.contents # 打印指針?biāo)傅膬?nèi)容 c_long(999) 
>>> pi.contents = c_long(1000) # 通過(guò)指針改變變量 i 的值 
>>> pi.contents # 打印指針?biāo)傅膬?nèi)容 c_long(1000)

下面例子說(shuō)明了結(jié)構(gòu)和數(shù)組的操作:
清單 4. ctypes 使用 C 語(yǔ)言數(shù)組和結(jié)構(gòu)體

>>> class POINT(Structure): # 定義一個(gè)結(jié)構(gòu)跪呈,內(nèi)含兩個(gè)成員變量 x段磨,y,均為 int 型 ... _fields_ = [("x", c_int), ... ("y", c_int)] ... 
>>> point = POINT(2,5)   # 定義一個(gè) POINT 類(lèi)型的變量庆械,初始值為 x=2, y=5 
>>> print point.x, point.y # 打印變量 2 5 
>>> point = POINT(y=5)   # 重新定義一個(gè) POINT 類(lèi)型變量薇溃,x 取默認(rèn)值 
>>> print point.x, point.y # 打印變量 0 5 
>>> POINT_ARRAY = POINT * 3 # 定義 POINT_ARRAY 為 POINT 的數(shù)組類(lèi)型 # 定義一個(gè) POINT 數(shù)組,內(nèi)含三個(gè) POINT 變量 
>>> pa = POINT_ARRAY(POINT(7, 7), POINT(8, 8), POINT(9, 9))     
>>> for p in pa: print p.x, p.y # 打印 POINT 數(shù)組中每個(gè)成員的值 ... 7 7 8 8 9 9

Python 訪問(wèn) C 語(yǔ)言 dll
通過(guò) ctypes 模塊缭乘,Python 程序可以訪問(wèn) C 語(yǔ)言編譯的 dll沐序,本節(jié)通過(guò)一個(gè)簡(jiǎn)單的例子,Python 程序 helloworld.py 中調(diào)用 some.dll 中的 helloworld 函數(shù)堕绩,來(lái)介紹 Python 程序如何調(diào)用 windows 平臺(tái)上的 dll策幼。
導(dǎo)入動(dòng)態(tài)鏈接庫(kù)清單 ctypes 導(dǎo)入 dll
from ctypes import windll # 首先導(dǎo)入 ctypes 模塊的 windll 子模塊 somelibc = windll.LoadLibrary(some.dll) # 使用 windll 模塊的 LoadLibrary 導(dǎo)入動(dòng)態(tài)鏈接庫(kù)
訪問(wèn)動(dòng)態(tài)鏈接庫(kù)中的函數(shù)清單 ctypes 使用 dll 中的函數(shù)
somelibc. helloworld() # 這樣就可以得到 some.dll 的 helloworld 的返回值。

整個(gè) helloworld.py 是這樣的:
清單 7. Python helloworld 代碼

from ctypes import windll def callc(): # load the some.dll 
somelibc = windll.LoadLibrary(some.dll) 
print somelibc. helloworld() 
if __name__== “__main__”: callc()

在命令行運(yùn)行 helloworld.py奴紧,在 console 上可以看到 some.dll 中 helloworld 的輸出特姐。
清單 8. Python hellpworld Windows command console 運(yùn)行輸出
C:>python C:\python\test\helloworld.py Hello World! Just a simple test.
Python 調(diào)用 C 語(yǔ)言 so
通過(guò) ctypes 模塊,Python 程序也可以訪問(wèn) C 語(yǔ)言編譯的 so 文件黍氮。與 Python 調(diào)用 C 的 dll 的方法基本相同唐含,本節(jié)通過(guò)一個(gè)簡(jiǎn)單的例子浅浮,Python 程序 helloworld.py 中調(diào)用 some.so 中的 helloworld 函數(shù),來(lái)介紹 Python 程序如何調(diào)用 linux 平臺(tái)上的 so捷枯。
導(dǎo)入動(dòng)態(tài)鏈接庫(kù)清單 ctypes 導(dǎo)入 so
from ctypes import cdll # 首先導(dǎo)入 ctypes 模塊的 cdll 子模塊滚秩,注意 linux 平臺(tái)上使用 cdll 的,而不是 windll淮捆。

somelibc = cdll.LoadLibrary(“./some.so”) # 使用 cdll 模塊的 LoadLibrary 導(dǎo)入動(dòng)態(tài)鏈接庫(kù)

訪問(wèn)動(dòng)態(tài)鏈接庫(kù)中的函數(shù)清單 ctypes 使用 so 中的函數(shù)

somelibc. helloworld() # 使用方法與 windows 平臺(tái)上是一樣的郁油。

整個(gè) helloworld.py 是這樣的:
清單 11. Python helloworld 代碼

from ctypes import cdll def callc(): # load the some.so 
somelibc = cdll.LoadLibrary(some.so) print somelibc. helloworld() 
if __name__== “__main__”: callc()

在命令行運(yùn)行 helloworld.py,在 linux 標(biāo)準(zhǔn)輸出上可以看到 some.so 中 helloworld 的輸出攀痊。
清單 12. Python hellpworld Linux shell 運(yùn)行輸出

[root@linux-790t] python ./helloworld.py Hello World! Just a simple test.

Python 程序和 C 程序整合實(shí)例
以下我們舉例用 Python 來(lái)實(shí)現(xiàn)一個(gè)小工具桐腌,用來(lái)實(shí)現(xiàn) hash 算法,查看文件的校驗(yàn)和(MD5,CRC,SHA1 等等)苟径。通過(guò)查看文件的校驗(yàn)和案站,可以知道文件在傳輸過(guò)程中是否被破壞或篡改。
Hash涩笤,一般翻譯做“散列”嚼吞,也有直接音譯為"哈希"的,就是把任意長(zhǎng)度的輸入(又叫做預(yù)映射蹬碧,pre-image)舱禽,通過(guò)散列算法,變換成固定長(zhǎng)度的輸出恩沽,該輸出就是散列值誊稚。這種轉(zhuǎn)換是一種壓縮映射,也就是罗心,散列值的空間通常遠(yuǎn)小于輸入的空間里伯,不同的輸入可能會(huì)散列成相同的輸出,而不可能從散列值來(lái)唯一的確定輸入值渤闷。簡(jiǎn)單的說(shuō)就是一種將任意長(zhǎng)度的消息壓縮到某一固定長(zhǎng)度的消息摘要的函數(shù)疾瓮。
由于相對(duì) C 語(yǔ)言來(lái)說(shuō),Python 的運(yùn)行效率較低飒箭,因此我們的 Python 小工具利用一個(gè)已有的 C 語(yǔ)言的動(dòng)態(tài)鏈接庫(kù) (hashtcalc.dll) 來(lái)實(shí)現(xiàn)我們的程序狼电。本例中,我們運(yùn)用 wxPython 編寫(xiě)簡(jiǎn)單的 GUI 界面弦蹂,通過(guò) python 調(diào)用 hashtcalc.dll 的接口計(jì)算文件的校驗(yàn)和肩碟,然后輸出在界面上。
架構(gòu)圖
圖 1. 工具的架構(gòu)圖

圖 1. 工具的架構(gòu)圖
hashcalc.dll 接口描述
函數(shù)名:calc_CRC32
函數(shù):char* calc_CRC32(char filename);
參數(shù):文件名
返回值:字符串
說(shuō)明:該函數(shù)對(duì)輸入的文件內(nèi)容進(jìn)行計(jì)算凸椿,并且返回它的 CRC32
函數(shù)名:calc_MD5
函數(shù):char
calc_MD5(char filename);
參數(shù):文件名
返回值:字符串
說(shuō)明:該函數(shù)對(duì)輸入的文件內(nèi)容進(jìn)行計(jì)算削祈,并且返回它的 MD5
函數(shù)名:calc_SHA1
函數(shù):char
calc_SHA1 (char *filename);
參數(shù):文件名
返回值:字符串
說(shuō)明:該函數(shù)對(duì)輸入的文件內(nèi)容進(jìn)行計(jì)算,并且返回它的 SHA1
HashcalcAdapter 代碼
HashcalcAdapter.py 實(shí)現(xiàn)了一個(gè) python 的 class HashcalcAdapter,HashcalcAdapter 對(duì) hashtcalc.dl 的 C 語(yǔ)言接口進(jìn)行了封裝髓抑,使得其他 python 模塊可以直接通過(guò) HashcalcAdapter 使用 hashtcalc.dll 中實(shí)現(xiàn)的 hash 算法咙崎。具體的代碼如下:
清單 13. HashcalcAdapter.py 代碼

from ctypes import windll 
from ctypes import * 
class HashcalcAdapter(object): 
  def __init__(self, dllpath): 
    self._dllpath = dllpath self._libc = windll.LoadLibrary(self._dllpath)
  def calc_CRC32(self, filename):
    new_filename = c_char_p(filename) 
    return self._libc.calc_CRC32(new_filename) def calc_MD5(self, filename): 
    new_filename = c_char_p(filename)
    return self._libc.calc_MD5(new_filename)
   def calc_SHA1(self, filename):
    new_filename = c_char_p(filename)
    return self._libc.calc_SHA1(new_filename)

運(yùn)行界面
圖 2. 工具的運(yùn)行界面

圖 2. 工具的運(yùn)行界面

轉(zhuǎn)載自:https://www.ibm.com/developerworks/cn/linux/l-cn-pythonandc/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市启昧,隨后出現(xiàn)的幾起案子叙凡,更是在濱河造成了極大的恐慌,老刑警劉巖密末,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異跛璧,居然都是意外死亡严里,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)追城,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)刹碾,“玉大人,你說(shuō)我怎么就攤上這事座柱∶灾模” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵色洞,是天一觀的道長(zhǎng)戏锹。 經(jīng)常有香客問(wèn)我,道長(zhǎng)火诸,這世上最難降的妖魔是什么锦针? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮置蜀,結(jié)果婚禮上奈搜,老公的妹妹穿的比我還像新娘。我一直安慰自己盯荤,他們只是感情好馋吗,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著秋秤,像睡著了一般宏粤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上航缀,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天商架,我揣著相機(jī)與錄音,去河邊找鬼芥玉。 笑死蛇摸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的灿巧。 我是一名探鬼主播赶袄,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼揽涮,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了饿肺?” 一聲冷哼從身側(cè)響起蒋困,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎敬辣,沒(méi)想到半個(gè)月后雪标,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溉跃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年村刨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撰茎。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嵌牺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出龄糊,到底是詐尸還是另有隱情逆粹,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布炫惩,位于F島的核電站僻弹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏诡必。R本人自食惡果不足惜奢方,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望爸舒。 院中可真熱鬧蟋字,春花似錦、人聲如沸扭勉。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)涂炎。三九已至忠聚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唱捣,已是汗流浹背两蟀。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留震缭,地道東北人赂毯。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親党涕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子烦感,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容