python调用c++动态库
python調用C++動態(tài)庫
- 生成C++動態(tài)庫
- 1.編譯成64位的dll庫
- 2. C++ 模板
- 3. 示例
- Python調用帶參數(shù)的動態(tài)庫
- python與c數(shù)據(jù)類型
- int、long、float、double參數(shù)
- 參數(shù)聲明
- 字符與字符串參數(shù)
- C分配內存與釋放內存
- python與c的效率
生成C++動態(tài)庫
生成C++ 動態(tài)庫需要注意以下幾點:
1.編譯成64位的dll庫
如果64位的python調用32位的dll會報下面的錯誤:
OSError: [WinError 193] %1 不是有效的 Win32 應用程序。這種錯誤的原因基本上都是64為的python調用了32位的動態(tài)庫。
解決的方法是生成64位的動態(tài)庫。安裝了visual studio可以使用:
x64的命令行窗口進行編譯。編譯命令是:
2. C++ 模板
頭文件的模板如下:
//dll.h #ifndef DLL_EXPORT #define DECLDIR __declspec(dllimport) #else #define DECLDIR __declspec(dllexport) #endifc++源文件的模板如下:
//hello.cpp #include "stdio.h" #include <iostream> #include <string.h>#ifdef __cplusplus extern "C" { #endif #define DLL_EXPORT #include "dll.h"using namespace std;#pragma execution_character_set("utf-8")DECLDIR void hello(void){printf("hello world");} DECLDIR int add_int(int a,int b){return a+b; } DECLDIR float add_float(float a,float b){return a+b; } DECLDIR double add_double(double a,double b){return a+b; } DECLDIR char pass_char(char c){printf("%c\n",char(c));return c; } DECLDIR wchar_t pass_wchar(wchar_t wc){wcout.imbue(locale("chs"));wcout<< wc;return wc; } DECLDIR char* pass_str(char *s){printf("%s\n",s);return strcat(s,"return"); } DECLDIR wchar_t* pass_wstr(wchar_t*s,wchar_t wc){wcout<< s;wchar_t *p = wcschr(s,wc);return p;}DECLDIR int* get_memory(int n) {int *p = new int[n];for(int i = 0; i < n; i++){p[i] = i;}return p; }DECLDIR void free_memory(int *p) {if(p)delete [] p; } DECLDIR int find_num(int target,int *p,int n){int i;for (i=0;i<n;i++){if (p[i]== target)return i;}return -1;}#ifdef __cplusplus } #endif3. 示例
c++程序見第二節(jié)
python程序如下:
Python調用帶參數(shù)的動態(tài)庫
第一節(jié)的示例是沒有任何參數(shù)的,屬于最簡單的情況。如何傳遞以及返回參數(shù),才是python調用動態(tài)庫的要點。
python與c數(shù)據(jù)類型
在ctypes中定義python互相對應的參數(shù)類型。
| 布爾 | c_bool | bool |
| 整型 | c_int | int |
| 長整型 | c_long | long |
| 浮點 | c_float | float |
| 雙精度 | c_double | double |
| 字符 | c_char | char |
| 寬字符 | c_wchar | wchar_t |
| 字符串 | c_char_p | char* |
| 寬字符串 | c_wchar_p | wchar_t * |
| 指針 | c_void_p | void * |
int、long、float、double參數(shù)
標準的dll調用需要明確傳入?yún)?shù)和返回參數(shù),否則系統(tǒng)會默認為所有參數(shù)為整型。比如:
//hello.cpp #include "stdio.h" #include <iostream>#ifdef __cplusplus extern "C" { #endif #define DLL_EXPORT #include "dll.h"using namespace std;DECLDIR void hello(void){printf("hello world");} DECLDIR int add_int(int a,int b){return a+b; } DECLDIR float add_float(float a,float b){return a+b; } DECLDIR double add_double(double a,double b){return a+b; }#ifdef __cplusplus } #endif from ctypes import * lib_path = './hello.dll' dlllib = cdll.LoadLibrary(lib_path) ret_i =dlllib.add_int(1,200) ret_f = dlllib.add_float(c_float(1.1),c_float(2.1)) print(ret_i,ret_f)此時程序返回的結果為:
201 1094533517
參數(shù)聲明
解決辦法是顯式聲明傳入和返回參數(shù)。
from ctypes import * lib_path = './hello.dll' dlllib = cdll.LoadLibrary(lib_path) ret_i =dlllib.add_int(1,200) dlllib.add_float.argtypes=[c_float,c_float] dlllib.add_float.restype = c_float ret_f = dlllib.add_float(c_float(1.1),c_float(2.1)) print(ret_i,ret_f)此時結果為:
201 3.1999998092651367字符與字符串參數(shù)
傳遞單個字符,可以使用c_char或者c_wchar,如果要傳遞字符串則需要c_char_p和c_wchar_p:
from ctypes import * lib_path = './hello.dll' dlllib = cdll.LoadLibrary(lib_path) dlllib.pass_char.argtypes=[c_char] dlllib.pass_char.restype = c_char ret_c = dlllib.pass_char(b"A") dlllib.pass_wchar.argtypes=[c_wchar] dlllib.pass_wchar.restype = c_wchar ret_w = dlllib.pass_wchar("學")dlllib.pass_str.argtypes=[c_char_p] dlllib.pass_str.restype = c_char_pret_s = dlllib.pass_str(b"test string ") dlllib.pass_wstr.argtypes=[c_wchar_p,c_wchar] dlllib.pass_wstr.restype = c_wchar_p ret_sw = dlllib.pass_wstr("世界真奇妙","好")print("------") print("pass_char",str(ret_c.decode("utf8"))) print("pass_wchar",ret_w) print("pass_str",str(c_char_p(ret_s).value.decode("utf8"))) print("pass_wstr",ret_sw)需要注意的是,c++對寬字符的處理比較麻煩,如果返回的字符串被修改,需要特別注意,因為返回的可能是亂碼。
------ pass_char A pass_wchar 學 pass_str test string return pass_wstr 真奇妙 A 學test string 世界真奇妙C分配內存與釋放內存
分配內存后,返回的是一個指針。
from ctypes import * lib_path = './hello.dll' dlllib = cdll.LoadLibrary(lib_path) dlllib.get_memory.argtypes=[c_int] dlllib.get_memory.restype = POINTER(c_int) ret_int = dlllib.get_memory(20) print("get:",ret_int) int_array = [ret_int[i] for i in range(20)] print(int_array)dlllib.free_memory.restype = c_void_p dlllib.free_memory(ret_int) get: <__main__.LP_c_long object at 0x00000272E0718040> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]python與c的效率
使用python與C混合編程的意義在于C的處理速度快,畢竟python是解釋型語音。比如通過循環(huán)查找數(shù)組里面的數(shù)值:
from ctypes import * import line_profiler import sysdef c_find(a):lib_path = './hello.dll'dlllib = cdll.LoadLibrary(lib_path)dlllib.find_num.argtypes=[c_int,POINTER(c_int),c_int]dlllib.find_num.restype = c_intret_f = dlllib.find_num(5,a,len(a))return ret_fdef p_find(a):for i in range(len(a)):if a[i]==5:return ireturn -1def main():a = [20]*100000a.append(5)arr_d = (c_int * len(a))(*(i for i in a))lib_path = './hello.dll'dlllib = cdll.LoadLibrary(lib_path)dlllib.find_num.argtypes=[c_int,POINTER(c_int),c_int]dlllib.find_num.restype = c_intdlllib.find_num(5,arr_d,len(arr_d))p_find(a)profile = line_profiler.LineProfiler(main) profile.enable() main() profile.disable() profile.print_stats(sys.stdout)結果:
Timer unit: 1e-07 sTotal time: 0.0549094 s File: p1.py Function: main at line 21Line # Hits Time Per Hit % Time Line Contents ==============================================================21 def main():22 1 3110.0 3110.0 0.6 a = [20]*10000023 1 2200.0 2200.0 0.4 a.append(5)24 1 299069.0 299069.0 54.5 arr_d = (c_int * len(a))(*(i for i in a))25 1 11.0 11.0 0.0 lib_path = './hello.dll'26 1 9016.0 9016.0 1.6 dlllib = cdll.LoadLibrary(lib_path)27 1 428.0 428.0 0.1 dlllib.find_num.argtypes=[c_int,POINTER(c_int),c_int]28 1 31.0 31.0 0.0 dlllib.find_num.restype = c_int29 1 1576.0 1576.0 0.3 dlllib.find_num(5,arr_d,len(arr_d))30 1 233653.0 233653.0 42.6 p_find(a)Process finished with exit code 0數(shù)組的大小是100001個,要選擇的元素在最后一個。純查找時間python為233653個時間單位,而c為1576。當然傳遞數(shù)組需要很長的時間。這是額外的花銷。需要綜合考慮是否采用動態(tài)庫,因為參數(shù)準備與傳遞需要很大的花銷。
總結
以上是生活随笔為你收集整理的python调用c++动态库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言 人事管理系统练习
- 下一篇: h2数据库学习----h2数据库基本使用