ctypes 是 python 标准库中的一个模块,用于调用动态链接库(如 .dll、.so、.dylib)中的 c 函数,并与 c 兼容的数据类型进行交互。它允许 python 程序直接与用 c/c++ 编写的共享库进行交互,而无需编写额外的绑定代码(如使用 cython 或 swig)。这在需要高性能计算、复用已有 c 库或操作系统底层接口时非常有用。
主要功能
- 加载动态链接库
- windows:
ctypes.windll/ctypes.cdll - linux/macos:
ctypes.cdll - 示例:
- windows:
import ctypes libc = ctypes.cdll("libc.so.6") # linux # 或 msvcrt = ctypes.cdll("msvcrt.dll") # windows- 调用 c 函数
- 加载后可像普通函数一样调用:
result = libc.printf(b"hello, %s\n", b"world")
- 数据类型映射
ctypes提供了与 c 类型对应的 python 类型,例如:- 示例结构体
class point(ctypes.structure): _fields_ = [("x", ctypes.c_int), ("y", ctypes.c_int)] p = point(10, 20)c_int,c_char,c_double,c_void_p等- 数组:
c_int * 10 - 结构体:继承
ctypes.structure - 联合体:继承
ctypes.union
- 数组:
- 指定函数参数和返回类型
- 默认情况下,
ctypes假设函数返回c_int,参数按 c 的默认规则转换。 - 可显式设置:
- 默认情况下,
libc.malloc.argtypes = [ctypes.c_size_t] libc.malloc.restype = ctypes.c_void_p
- 回调函数(callback)
- 可将 python 函数作为 c 函数指针传入:python
cmpfunc = ctypes.cfunctype(ctypes.c_int, ctypes.c_int, ctypes.c_int) def py_cmp(a, b): return a - b cmp_func = cmpfunc(py_cmp)- 内存管理
- 可通过
ctypes.create_string_buffer()创建可变内存块 - 注意:不当使用可能导致段错误(segmentation fault)
- 可通过
使用场景
- 调用系统 api(如 windows api)
- 复用高性能 c 库(如数学计算、图像处理)
- 与硬件驱动或嵌入式设备通信
- 快速原型开发,避免重写 c 代码
检查屏幕状态
通过cypes加载windows api的user32.dll动态链接库
user32.dll是windows系统中负责用户界面相关功能的核心库,提供了窗口管理、消息处理等功能
def check_screen_state():
user32 = ctypes.windll.user32
#getdc函数用于获取指定窗口的设备上下文(device context),0表示获取整个屏幕的dc,而不是特定窗口的
hdc = user32.getdc(0)
try:
# 获取设备的特定能力值,109对应windowsapi中的sm_cmonitors常量,用于获取系统中显示器的数量
result = user32.getdevicecaps(hdc, 109) # 目的是检查系统中是否有显示器连接
if result == 0:
current_state = 'off'
else:
'''
systemparametersinfow是windowsapi中的一个核心函数,用于获取或设置各种系统参数。
后缀w表示这是unicode版本的函数,用于处理宽字符
bool systemparametersinfow(
uint uiaction, // 要执行的操作
uint uiparam, // 操作相关的参数
pvoid pvparam, // 数据缓冲区指针
uint fwinini // 更新配置文件的标志
);
- 当调用 systemparametersinfow(16, 0, none, 0) 时:
- uiaction = spi_getscreensaverrunning (16)
- uiparam = 0 (此操作不需要额外参数)
- pvparam = none (在 python 中,这里会返回布尔值)
- fwinini = 0 (不需要更新配置文件)
- 返回值:如果屏幕保护程序正在运行,返回非零值;否则返回 0。
'''
is_screen_saver_running = user32.systemparametersinfow(16, 0, none, 0)
if is_screen_saver_running:
current_state = 'screensaver' // 屏幕保护程序运行
else:
# 参数 114 用于检查显示器电源管理是否已激活,对应windowsapi中的常量spi_gettpoweroffactive
is_monitor_off = user32.systemparametersinfow(114, 0, none, 0)
if is_monitor_off:
current_state = 'off' // 屏幕关闭
else:
current_state = 'on' // 屏幕亮起
except:
current_state = 'unknown' // 屏幕状态未知
finally:
user32.releasedc(0, hdc)
return current_state
注意事项
- 平台依赖性:不同操作系统/架构下,库名称、调用约定(calling convention)可能不同。
- abi 兼容性:需确保调用的函数签名与实际一致,否则程序可能崩溃。
- 安全性:
ctypes绕过了 python 的内存安全机制,错误使用可能导致严重问题。 - 性能开销:虽然调用的是原生代码,但频繁的 python ↔ c 转换仍有开销。
简单示例:调用 c 标准库的abs
import ctypes
# 加载 c 标准库(linux/macos)
libc = ctypes.cdll("libc.so.6") # macos 可能是 "libc.dylib"
# 设置函数签名
libc.abs.argtypes = [ctypes.c_int]
libc.abs.restype = ctypes.c_int
# 调用
print(libc.abs(-42)) # 输出: 42在 windows 上可使用
"msvcrt.dll"并调用abs。
总之,ctypes 是 python 与 c 世界之间的一座桥梁,强大但需谨慎使用。对于更复杂或高频的交互,也可考虑 cffi、pybind11 或 cython 等替代方案。
到此这篇关于python中的ctypes的文章就介绍到这了,更多相关python ctypes内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论