ctypes
是一個用於Python的外部函數庫。它提供C兼容的數據類型,並允許在DLL或共享庫中調用函數。它可以用來將這些庫封裝在純Python中
1.使用Visual Studio創建dll
點擊完成,創建dll導出函數,下代碼爲C++代碼
// test_dll.cpp : 定義 DLL 應用程序的導出函數。
//
#include "stdafx.h"
//用於簡單測試
extern "C" _declspec(dllexport) int add(int a, int b);
int add(int a, int b)
{
return a+b;
}
//用於指針的使用
extern "C" _declspec(dllexport) int * add_pointer(int a, int b);
int * add_pointer(int a, int b)
{
int *c = new int;
*c = a + b;
return c;
}
extern "C" _declspec(dllexport) int get_value(int *a);
int get_value(int *a)
{
int b = *a;
delete a;
return b;
}
//用於字符串使用
extern "C" _declspec(dllexport) char * str(char *a);
char * str(char *a)
{
return a;
}
//用於測試結構體使用
struct Rect{
int left;
int top;
int right;
int bottom;
};
extern "C" _declspec(dllexport) Rect struct_rect(Rect a);
Rect struct_rect(Rect a)
{
a.left += 5;
a.top += 5;
return a;
}
//用於數組測試
extern "C" _declspec(dllexport) int array1(int arr[]);
int array1(int arr[])
{
return arr[0];
}
2.ctypes引用dll調用函數
引用dll 有四個方法
CDLL(dllPath),WINDLL(dllPath),cdll.LoadLibrary(dllpath),windll.LoadLibrary(dllpath)
基本測試
from ctypes import *
dll = CDLL(r"C:\Users\DELL\Documents\visual studio 2013\Projects\test_dll\x64\Debug\test_dll.dll")#引入dll
num = dll.add(5,6)#調用函數
print(num)
ctypes支持的原生數據類型如下:
ctypes類型 |
C類型 |
Python類型 |
---|---|---|
c_bool |
_Bool |
bool (1) |
c_char |
char |
1-character string |
c_wchar |
wchar_t |
1-character unicode string |
c_byte |
char |
int/long |
c_ubyte |
unsigned char |
int/long |
c_short |
short |
int/long |
c_ushort |
unsigned short |
int/long |
c_int |
int |
int/long |
c_uint |
unsigned int |
int/long |
c_long |
long |
int/long |
c_ulong |
unsigned long |
int/long |
c_longlong |
__int64 or long long |
int/long |
c_ulonglong |
unsigned __int64 or unsigned long long |
int/long |
c_float |
float |
float |
c_double |
double |
float |
c_longdouble |
long double |
float |
c_char_p |
char * (NUL terminated) |
string or None |
c_wchar_p |
wchar_t * (NUL terminated) |
unicode or None |
c_void_p |
void * |
int/long or None |
指針使用
num1 = dll.add_pointer(5,6)
print(num1)
num1 = dll.get_value(num1)
porint(num1)
如果如上面代碼直接獲取指針和引用指針會64位的python會報出如:
OSError: exception: access violation reading 0xFFFFFFFFF179FBC0
如下圖:
而且指針成了負數,應該事因爲ctypes默認的返回類型都是有符號int, 最高位表示正負的原因
解決辦法:
指定dll 函數的返回類型如下代碼
dll.add_pointer.restype = c_uint64 #指定函數返回指針類型爲c_uint64
num1_pointer =dll.add_pointer(5,6)
num1 = dll.get_value(c_uint64(num1_pointer))#參數指針類型爲c_uint64
3.字符串使用
dll.str.restype = c_char_p #c_char_p對應char指針指定返回類型爲c_char_p
str = dll.str( c_char_p(bytes("可以",encoding="utf-8")))#字符串參數,將字符串解碼,再轉(c_char_p)
print(str.decode()) #字節編碼成字符串
4 結構體使用
結構體
struct Rect{
int left;
int top;
int right;
int bottom;
};
python 對應class類
class Rect(Structure):
_fields_ = [
("left", c_int),
("top", c_int),
("right", c_int),
("bottom", c_int),
]
結構體引用
class Rect(Structure):
_fields_ = [
("left", c_int),
("top", c_int),
("right", c_int),
("bottom", c_int),
]
rect = Rect(5,5,5,5)
dll.struct_rect.restype = Rect #確定返回類型爲Rect
rect = dll.struct_rect(rect) # 參數直接使用對象
print(rect.left,rect.top)
5數組的使用
arr = (c_uint*5)(1,2,3,4,5) #ctypes定義C類型數據方法
i = dll.array1(arr)
print(1)
numpy 數組傳入C/C++方法
arr1 = np.array([2, 3, 4])
if not arr1.flags['C_CONTIGUOUS']:
arr1 = np.ascontiguous(arr1, dtype=arr1.dtype) # 如果不是C連續的內存,必須強制轉換
arr1_point = cast(arr1.ctypes.data,POINTER(c_uint)) #轉換爲ctypes,這裏轉換後的可以直接利用ctypes轉換爲c中的int*,然後在c中使用