新聞中心
怎樣讓Python腳本與C++程序互相調用
二、Python調用C/C++

為甘泉等地區(qū)用戶提供了全套網(wǎng)頁設計制作服務,及甘泉網(wǎng)站建設行業(yè)解決方案。主營業(yè)務為做網(wǎng)站、成都網(wǎng)站設計、甘泉網(wǎng)站設計,以傳統(tǒng)方式定制建設網(wǎng)站,并提供域名空間備案等一條龍服務,秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!
1、Python調用C動態(tài)鏈接庫
Python調用C庫比較簡單,不經(jīng)過任何封裝打包成so,再使用python的ctypes調用即可。
(1)C語言文件:pycall.c
[html] view plain copy
/***gcc -o libpycall.so -shared -fPIC pycall.c*/
#include stdio.h
#include stdlib.h
int foo(int a, int b)
{
printf("you input %d and %d\n", a, b);
return a+b;
}
(2)gcc編譯生成動態(tài)庫libpycall.so:gcc -o libpycall.so -shared -fPIC pycall.c。使用g++編譯生成C動態(tài)庫的代碼中的函數(shù)或者方法時,需要使用extern "C"來進行編譯。
(3)Python調用動態(tài)庫的文件:pycall.py
[html] view plain copy
import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll("./libpycall.so")
lib.foo(1, 3)
print '***finish***'
(4)運行結果:
2、Python調用C++(類)動態(tài)鏈接庫
需要extern "C"來輔助,也就是說還是只能調用C函數(shù),不能直接調用方法,但是能解析C++方法。不是用extern "C",構建后的動態(tài)鏈接庫沒有這些函數(shù)的符號表。
(1)C++類文件:pycallclass.cpp
[html] view plain copy
#include iostream
using namespace std;
class TestLib
{
public:
void display();
void display(int a);
};
void TestLib::display() {
cout"First display"endl;
}
void TestLib::display(int a) {
cout"Second display:"aendl;
}
extern "C" {
TestLib obj;
void display() {
obj.display();
}
void display_int() {
obj.display(2);
}
}
(2)g++編譯生成動態(tài)庫libpycall.so:g++ -o libpycallclass.so -shared -fPIC pycallclass.cpp。
(3)Python調用動態(tài)庫的文件:pycallclass.py
[html] view plain copy
import ctypes
so = ctypes.cdll.LoadLibrary
lib = so("./libpycallclass.so")
print 'display()'
lib.display()
print 'display(100)'
lib.display_int(100)
(4)運行結果:
3、Python調用C/C++可執(zhí)行程序
(1)C/C++程序:main.cpp
[html] view plain copy
#include iostream
using namespace std;
int test()
{
int a = 10, b = 5;
return a+b;
}
int main()
{
cout"---begin---"endl;
int num = test();
cout"num="numendl;
cout"---end---"endl;
}
(2)編譯成二進制可執(zhí)行文件:g++ -o testmain main.cpp。
(3)Python調用程序:main.py
[html] view plain copy
import commands
import os
main = "./testmain"
if os.path.exists(main):
rc, out = commands.getstatusoutput(main)
print 'rc = %d, \nout = %s' % (rc, out)
print '*'*10
f = os.popen(main)
data = f.readlines()
f.close()
print data
print '*'*10
os.system(main)
(4)運行結果:
4、擴展Python(C++為Python編寫擴展模塊)
所有能被整合或導入到其它python腳本的代碼,都可以被稱為擴展??梢杂肞ython來寫擴展,也可以用C和C++之類的編譯型的語言來寫擴展。Python在設計之初就考慮到要讓模塊的導入機制足夠抽象。抽象到讓使用模塊的代碼無法了解到模塊的具體實現(xiàn)細節(jié)。Python的可擴展性具有的優(yōu)點:方便為語言增加新功能、具有可定制性、代碼可以實現(xiàn)復用等。
為 Python 創(chuàng)建擴展需要三個主要的步驟:創(chuàng)建應用程序代碼、利用樣板來包裝代碼和編譯與測試。
(1)創(chuàng)建應用程序代碼
[html] view plain copy
#include stdio.h
#include stdlib.h
#include string.h
int fac(int n)
{
if (n 2) return(1); /* 0! == 1! == 1 */
return (n)*fac(n-1); /* n! == n*(n-1)! */
}
char *reverse(char *s)
{
register char t, /* tmp */
*p = s, /* fwd */
*q = (s + (strlen(s) - 1)); /* bwd */
while (p q) /* if p q */
{
t = *p; /* swap move ptrs */
*p++ = *q;
*q-- = t;
}
return(s);
}
int main()
{
char s[BUFSIZ];
printf("4! == %d\n", fac(4));
printf("8! == %d\n", fac(8));
printf("12! == %d\n", fac(12));
strcpy(s, "abcdef");
printf("reversing 'abcdef', we get '%s'\n", \
reverse(s));
strcpy(s, "madam");
printf("reversing 'madam', we get '%s'\n", \
reverse(s));
return 0;
}
上述代碼中有兩個函數(shù),一個是遞歸求階乘的函數(shù)fac();另一個reverse()函數(shù)實現(xiàn)了一個簡單的字符串反轉算法,其主要目的是修改傳入的字符串,使其內容完全反轉,但不需要申請內存后反著復制的方法。
(2)用樣板來包裝代碼
接口的代碼被稱為“樣板”代碼,它是應用程序代碼與Python解釋器之間進行交互所必不可少的一部分。樣板主要分為4步:a、包含Python的頭文件;b、為每個模塊的每一個函數(shù)增加一個型如PyObject* Module_func()的包裝函數(shù);c、為每個模塊增加一個型如PyMethodDef ModuleMethods[]的數(shù)組;d、增加模塊初始化函數(shù)void initModule()。
python 字典調用C++函數(shù)
使用Python的ctypes,我們可以直接調用由C直接編譯出來的函數(shù)。其實就是調用動態(tài)鏈接庫中的函數(shù)。為什么我們需要這樣做呢,因為有些時候,我們可能需要一個性能上比較講究的算法,有些時候,我們可以在Python中使用已經(jīng)有了的現(xiàn)成的被封閉在動態(tài)鏈接庫中的函數(shù)。下面是如何調用的示例。
首先,我們用一個乘法來表示一個算法功能。下面是C的程序:
int?multiply(int?num1,?int?num2){???
return?num1?*?num2;
}????
如果在Windows下,你可能需要寫成下面這個樣子:
#include?windows.h?
BOOL?APIENTRYDll
Main(HANDLE?hModule,?DWORD?dwReason,?LPVOID?lpReserved){????
return?TRUE;
}?
__declspec(dllexport)?
intmultiply(int?num1,?int?num2){?
return?num1?*?num2;
}????
然后,自然是把這個C文件編成動態(tài)鏈接庫:
Linux下的編譯:
gcc?-c?-fPIC?libtest.c
gcc?-shared?libtest.o?-o?libtest.so????
Windows下的編譯:
cl?-LD?libtest.c?-libtest.dll????
于是在我們的Python中可以這樣使用:
(其中的libtest.so在Windows下改成libtest.dll即可)
from?ctypes?import?*
import?os
libtest?=?cdll.LoadLibrary(os.getcwd()?+?'/libtest.so')
print?libtest.multiply(2,?2)4????
注意:上面的Python腳本中需要把動態(tài)鏈接庫放到當前目錄中。
C語言程序如何調用python程序
下面是一個例子:
首先是python的一個簡單函數(shù)
class Hello:
def __init__(self, x):
self.a = x
def print(self, x=None):
print(x)
def xprint():
print("hello world")
if __name__ == "__main__":
xprint()
h = Hello(5)
h.print()1
下面是C語言
#include python3.4m/Python.h
#include stdio.h
#include stdlib.h
#include string.h
int main()
{
Py_Initialize();
// 將當前目錄加入sys.path
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
// 導入hello.py模塊
PyObject *pmodule = PyImport_ImportModule("hello");
// 獲得函數(shù)xprint對象,并調用,輸出“hello world\n”
PyObject *pfunc = PyObject_GetAttrString(pmodule, "xprint");
PyObject_CallFunction(pfunc, NULL);
// 獲得類Hello并生成實例pinstance,并調用print成員函數(shù),輸出“5 6\n”
PyObject *pclass = PyObject_GetAttrString(pmodule, "Hello");
PyObject *arg = Py_BuildValue("(i)", 5);
PyObject *pinstance = PyObject_Call(pclass, arg, NULL);
PyObject_CallMethod(pinstance, "print", "i", 6);
Py_Finalize();
return 0;
}
編譯命令如下:
gcc pyapi.c -lpython3.4m -o pyapi
python使用ctypes調用C編譯dll函數(shù)方法
在函數(shù)聲明加入前綴,如
__declspec(dllexport) int Fun(int a, int b)
否則在加載該dll時會提示找不到該符號
在windows下可以通過vs自帶的dumpbin工具查看可被調用符號
dumpbin /exports test.dll
C函數(shù)在調用過程中關于參數(shù)傳遞和壓棧由多種規(guī)定,作為dll提供給其他程序調用時,必須明確并統(tǒng)一為同一種調用規(guī)定,否則會導致棧破壞,編譯器負責具體實現(xiàn)調用規(guī)定,主要有以下幾種調用規(guī)定
python下調用C庫有多種方式,ctypes是其中一種比較方便的,調用時首先需要加載dll文件,根據(jù)C dll的調用規(guī)定不同需要使用不同接口,使用ctypes需要 import ctypes 庫
對于簡單的C函數(shù),例如 int add(int a, int b) , 此時就可以直接調用了,如
對于較復雜的C函數(shù)的參數(shù)情況,ctypes調用時對入?yún)⒑统霾妥鲆欢ㄌ幚?,這里分情況討論
以上包含了幾種主要的參數(shù)傳遞情況,ctypes也提供了一個較為完整的python類型和C類型的對照,如下:
網(wǎng)站題目:python與c調用函數(shù),c語言調用python
文章鏈接:http://www.dlmjj.cn/article/hsiiod.html


咨詢
建站咨詢
