本文介绍使用 Python 调用 C / C++ 编译得到的库文件中的函数。
包依赖
import ctypes
调用方法
将 C / C++ 函数编译为动态库文件
For C
gcc functionsName.c -fPIC -shared -o libName.so
For C++
g++ functionsName.cpp -fPIC -shared -o libName.so
注意:在编译动态库的时候 C++ 函数必须被指定为 extern “C”, 可以使用宏定义关键词,添加到函数声明前:
#define CEXT extern "C"
// then add the macro keywords before function name:
CEXT void helloWorld(){
...
}
导入Python
import ctypes
functionBranch = ctypes.cdll.LoadLibrary("./libName.so")
声明返回值与参数的数据类型
functionBranch.funcName.restype = ctypes.c_float
可选的数据类型有:
ctypes type | C type | Python Type |
---|---|---|
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_bool | bool | bool |
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 longlong | 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 | float |
c_char_p | char * | string or None |
c_wchar_p | wchar_t * | unicode or None |
c_void_p | void * | int/long or None |
对于指针类型: 添加 _p
到以上的数据类型前, 例如 c_int_p
指代 int*
。
声明 C-type arrays / Matrix 作为参数
简单的方式可以通过引入 numpy.ctypeslib
为 npct
并使用 ndpointer
函数声明指针:
import ctypes
import numpy as np
import numpy.ctypeslib as npct
radiats = ctypes.cdll.LoadLibrary("./libradiats.so")
radiats.dc_radiat.argtypes = [ctypes.c_float, ctypes.c_float, ctypes.c_float, npct.ndpointer(dtype = ctypes.c_float, ndim = 2, flags="C_CONTIGUOUS")]
aa = np.zeros([3, 3], dtype = ctypes.c_float)
strike = 20
dip = 30
rake = 0
radiats.dc_radiat(strike,dip,rake,aa)
print(aa)
以上代码同样声明了参数的数据类型, ndpointer
声明了一个 ctypes.c_float
的二维指针。
特别注意
C / C++ 的 float
类型位宽为 $32$;而Python 中的 float
类型与 np.float
的位宽为 $64$。因此在声明返回值数据类型 restype
与参数数据类型 argtypes
时候要注意保持位宽的一致性,特别是在传值过程中涉及矩阵数据类型转换的过程,如果位宽不一致会导致传值错误。