Python - ctypes

基本概念

库是写好的,现有的,成熟的,可以复用的代码。本质上来说,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库动态库。所谓静态、动态是指链接方式。

静态库
静态库的扩展名一般为".a"或".lib",静态库在编译时会被直接整合到目标程序中,编译成功的可执行文件可独立运行。

动态库
动态库的扩展名一般为".so"或".dll",动态函数库在编译的时候,在程序里只有一个指向的位置,当可执行文件需要使用到函数库的机制时,程序才会去读取函数库来使用;编译成功的可执行文件无法独立运行。
生成动态库: gcc xxx.c -fPIC -shared -std=c11 -o libxxx.so

C 与 C++

C++ 不是 C 严格意义上的超集

大部分的合法 C 代码是合法的 C++ 代码,但并不是所有的都是,举例如下:

  • C++ 有更多的关键字,如:class、new。在 C 语言里使用了这些关键字的程序到 C++ 肯定不合法
  • 字符串字面量在 C 里面是 char 数组,在 C++ 里面是 const char 数组
  • ‘A’ 的类型在 C 里是 int,在 C++ 里是 char
  • 布尔表达式的结果在 C 里是 int,在 C++ 里是 bool

Python 调用 C 的方式

ctypes 库

ctypes 是 Python 的外部函数库。它提供了与 C 语言兼容的数据类型,并允许调用 so 或 dll 动态库中的函数。可使用该模块以纯 Python 形式对这些库进行封装。

Python 的 C-API

使用 Python 开放的 C 语言 API 编写 C 语言扩展模块,可以将 C/C++ 代码嵌入到 Python 中

SWIG

SWIG 是简单包装器和接口生成器,是一个适用于多种语言的工具。它能够自动化地生成 C/C++ 的包装代码,并在 Python 等高级语言中运行。

方法对比

ctypes 库可以以纯 Python 形式对库进行封装。适用于给定 C 动态库或者源程序的情况。
Python 的 C-API 方法比较复杂,且较为底层,效率高。适用于性能要求较高,给定 Python 代码使用 C/C++ 开发的场景。
SWIG 可以自动生成 C/C++ 的包装代码,比较方便,适用于给定 C/C++ 源程序的情况。

ctypes 库 的使用

加载库和取出函数

通过 ctypes 中的 CDLL 函数和 WinDLL 函数分别可以加载".so"和".dll"格式的动态库,并取出函数

import ctypes
libxxx_so = ctypes.CDLL("./libxxx.so")
func = libxxx_so.func_name  #func_name 是库的导出函数

设定参数类型和返回值类型

argtypes 属性用于设置函数的参数类型
restype 属性用于设置函数的返回值类型,默认函数返回值是 c_int 型

ctypes支持的原生数据类型如下:

ctypes 类型C 类型Python 类型
c_bool_Boolbool (1)
c_charchar单字符字节串对象
c_wcharwchar_t单字符字符串
c_bytecharint
c_ubyteunsigned charint
c_shortshortint
c_ushortunsigned shortint
c_intintint
c_uintunsigned intint
c_longlongint
c_ulongunsigned longint
c_longlong__int64 或 long longint
c_ulonglongunsigned __int64 或 unsigned long longint
c_size_tsize_tint
c_ssize_tssize_t 或 Py_ssize_tint
c_time_ttime_tint
c_floatfloatfloat
c_doubledoublefloat
c_longdoublelong doublefloat
c_char_pchar* (以 NUL 结尾)字节串对象或 None
c_wchar_pwchar_t* (以 NUL 结尾)字符串或 None
c_void_pvoid*int 或 None

调用外部 C 函数

将准备好的参数传入,调用 C 函数,并将返回的 ctypes 类型转换为 Python 类型

代码示例

现有库 libsum.so,库中有一个函数 sum,接收一个整型数组和数组长度,返回数组所有元素之和,函数声明如下:
int sum(int* arr, int len)

用 Python 编写 sum 函数对 libsum.so 中的sum函数进行封装,封装的函数 sum 接收一个整型列表,返回列表中所有元素之和。

内容如下:

def sum(int_list):
    import ctypes
    libsum_so = ctypes.CDLL("C:/Users/yd/Desktop/libsum.so")

    for item in int_list:
        assert isinstance(item, int)
    
    func = libsum_so.sum

    length = len(int_list)
    first_arg_type = ctypes.c_int * length

    func.argtypes = [first_arg_type, ctypes.c_int]
    func.restype = ctypes.c_int

    first_arg = first_arg_type()
    for i in range(length):
        first_arg[i] = int_list[i]
    
    res = int(func(first_arg, length))

    return res

测试:
print(sum([5, 6, 7, 8]))

结果:

26

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值