python c 语言接口,## 人生苦短我用python[0x08] 使用ctypes调用c语言接口 ##
文章內(nèi)容為原創(chuàng),歡迎轉(zhuǎn)載請(qǐng)注明出處
作者: EflyPro->晦明禪師
1.背景
python作為解析語(yǔ)言大規(guī)模應(yīng)用在各個(gè)領(lǐng)域,c語(yǔ)言作為系統(tǒng)級(jí)別的語(yǔ)言廣泛應(yīng)用在基礎(chǔ),系統(tǒng),網(wǎng)絡(luò)等底層服務(wù)當(dāng)中,可以說(shuō)python和c語(yǔ)言之間各有擅長(zhǎng)和不擅長(zhǎng)的地方,今天文章討論的是,如何使用python開發(fā)的程序調(diào)用c語(yǔ)言寫的庫(kù)文件,使得兩種語(yǔ)言得以互補(bǔ)。
2.ctypes
ctypes是python自帶的用于跟c語(yǔ)言做對(duì)接的庫(kù),里面提供了針對(duì)c語(yǔ)言數(shù)據(jù)類型,除此還提供了加載動(dòng)態(tài)庫(kù)和調(diào)用動(dòng)態(tài)庫(kù)函數(shù)的功能,比如在windows下可以加載dll文件并可以調(diào)用里面的函數(shù)接口,在linux下可以加載so文件調(diào)用里面的函數(shù)接口。
3.例子
我們使用ctypes庫(kù),調(diào)用c語(yǔ)言經(jīng)常用到的printf函數(shù)作為一個(gè)簡(jiǎn)單的例子,下面是具體python代碼
>>> import ctypes
>>> ctypes.cdll.LoadLibrary('libc.so.6')
>>> libc = ctypes.CDLL('libc.so.6')
>>> libc.printf
>>> libc.printf("hello %s\n", "world!")
hello world!
13
>>>
簡(jiǎn)單解析一下上面的幾行代碼,我們知道printf函數(shù)是c語(yǔ)言基礎(chǔ)庫(kù),放在libc.so文件里面,以例子所在Ubuntu 16.04 x64 Server,具體路徑是 /lib/x86_64-linux-gnu/libc.so.6,首先是用ctypes加載對(duì)應(yīng)的so文件,因?yàn)閘ibc是系統(tǒng)基礎(chǔ)庫(kù)文件,所以不用指定絕對(duì)路徑,加載完之后就實(shí)例化libc的對(duì)象,比如程序的libc,然后就可以調(diào)用libc里面的printf函數(shù)了。根據(jù)printf的函數(shù)原型,除了輸出字符信息之外,還返回輸出信息的長(zhǎng)度,所以我們看到除了輸出hello world!之外,下面返回的14就是字符串的長(zhǎng)度。
4.實(shí)戰(zhàn)
上面3的例子是調(diào)用系統(tǒng)自帶的庫(kù),下面我們自己嘗試用c語(yǔ)言編寫一個(gè)動(dòng)態(tài)庫(kù),然后使用ctypes調(diào)用里面的函數(shù)接口。我們先用c語(yǔ)言編寫一個(gè)最簡(jiǎn)單的庫(kù),然后這個(gè)庫(kù)里面只有一個(gè)函數(shù)接口。
foo.h
#ifndef foo_h__
#define foo_h__
extern void foo(void);
#endif // foo_h__
foo.c
#include
void foo(void)
{
printf("Hello, I'm a shared library");
}
編譯foo so動(dòng)態(tài)庫(kù)
gcc -c -Wall -Werror -fpic foo.c
gcc -shared -o libfoo.so foo.o
一切順利的話,當(dāng)前目錄下會(huì)有一個(gè)libfoo.so的動(dòng)態(tài)庫(kù)文件,下面我們寫一個(gè)main.c的程序測(cè)試一下這個(gè)libfoo.so庫(kù)
main.c
#include
#include "foo.h"
int main(void)
{
printf("This is a shared library test...");
foo();
return 0;
}
編譯main.c文件
#這里需要用-L參數(shù)告訴gcc我們的so庫(kù)所在目錄,要不gcc會(huì)找不到我們的庫(kù)
gcc -L/tmp/test -Wall -o test main.c -lfoo
一切順利之后會(huì)產(chǎn)生test的執(zhí)行文件,我們執(zhí)行它,不過(guò)執(zhí)行之前我們先要定義一下系統(tǒng)庫(kù)路徑,要不執(zhí)行test的時(shí)候系統(tǒng)會(huì)提示找不到庫(kù)文件
export LD_LIBRARY_PATH=/tmp/test:$LD_LIBRARY_PATH
./test
順利輸出信息。我們知道我們的libfoo.so是正常可用的,那么我們就寫一個(gè)python程序去調(diào)用我們的libfoo里面的foo函數(shù)接口。
main.py
>>> import ctypes
>>> ctypes.cdll.LoadLibrary('/tmp/test/libfoo.so')
>>> libfoo = ctypes.CDLL('libfoo.so')
>>> libfoo = ctypes.CDLL('/tmp/test/libfoo.so')
>>> libfoo
>>> libfoo.foo()
Hello, I'm a shared library27
>>>
具體代碼其實(shí)跟3.例子類似,只是因?yàn)槲覀兊膸?kù)是非系統(tǒng)的,所以要指定絕對(duì)路徑而已,字符串最后的27是輸出字符串的長(zhǎng)度。
由睿江云提供,想了解更多,請(qǐng)登陸www.eflycloud.com
總結(jié)
以上是生活随笔為你收集整理的python c 语言接口,## 人生苦短我用python[0x08] 使用ctypes调用c语言接口 ##的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
                            
                        - 上一篇: JSBox 移动端 JavaScript
 - 下一篇: 二阶差分方程预测模型matlab程序,差