python中ctypes使用

news/2024/9/23 0:29:22/

前段时间接到了一个需求是给一个蓝牙的SDK测试接口的稳定性,将SDK的接口文档给你了,需要每个接口都写一个对应的测试用例,SDK 是用c写的,而我python用的比较熟练些,所有记录下在ctypes库的使用方法。

pythonc_2">1 python和c中类型映射

ctypes中数据类型

ctypes 类型C 类型Python 数据类型
c_bool_Boolbool (1)
c_charchar单字符字节串对象
c_wcharwchar_t单字符字符串
c_bytecharint
c_ubyteunsigned charint
POINTER(c_ubyte)uchar*int
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_floatfloatfloat
c_doubledoublefloat
c_longdoublelong doublefloat
c_char_pchar * (NUL terminated)字节串对象或 None
c_wchar_pwchar_t * (NUL terminated)字符串或 None
c_void_pvoid *int 或 None

2 加载共享库

python">
import ctypes  
# 加载本地的共享库,路径根据实际情况调整  
lib = ctypes.CDLL('./libexample.so')  # Linux/macOS平台  
# lib = ctypes.WinDLL('example.dll')  # Windows平台

3 调用函数

python"># 设置参数类型  
lib.add.argtypes = [ctypes.c_int, ctypes.c_int]  # 设置返回类型  
lib.add.restype = ctypes.c_int  # 调用C函数  
result = lib.add(2, 3)  
print(result)  # 输出:5

4 操作指针

在ctypes中,你可以使用pointer和byref来操作指针。

python"># 创建一个整数数组  
arr = (ctypes.c_int * 5)(1, 2, 3, 4, 5)  # 获取指向数组首元素的指针  
ptr = ctypes.pointer(arr)  # 通过指针访问数组元素  
print(ptr[0])  # 输出:1  # 使用byref创建指向变量的指针  
x = ctypes.c_int(10)  
px = ctypes.byref(x)  # 通过指针修改变量的值  
lib.increment(px)  # 假设有一个increment函数用于增加整数的值  
print(x.value)  # 输出:11
python"># 调用系统的库函数测试
from ctypes import c_int, c_float, create_string_buffer, CDLL, byrefc_lib = CDLL('/lib/x86_64-linux-gnu/libc.so.6')i = c_int()
f = c_float()
s = create_string_buffer(b"\000" * 32)
print(i.value, f.value, repr(s.value))# brref 传入数据类型返回指针的地址, create_string_buffer返回的是指针
c_lib.sscanf(b"1 3.14 Hello", b"%d %f %s", byref(i), byref(f), s)
print(i.value, f.value, repr(s.value))
python">from ctypes import c_int, POINTER, cdlli = c_int(42)   # 创建一个int类型变量
pi = POINTER(c_int)(i)  # 定义一个指向int类型的指针print(pi.contents)   # 打印指针指向的内存地址
print(pi.contents.value)   # 打印指针指向的值# 定义C库中的函数原型
sum_func = cdll.LoadLibrary('./test1.so').sums
sum_func.argtypes = [POINTER(c_int), POINTER(c_int)]    # 定义函数参数类型为指针类型
sum_func.restype = POINTER(c_int)   # 定义函数返回值类型为指针类型pointer = POINTER(c_int)
# 调用sum()函数
a = c_int(1)
b = c_int(2)
c = sum_func(pointer(a), pointer(b))   # 将a、b的地址传递给sum()函数
print(c.contents.value)   # 打印返回值

5 操作结构体和联合体

你需要定义结构体或联合体的类型,然后可以创建实例、访问其成员等。

python"># 定义C语言的结构体类型  
class Point(ctypes.Structure):  _fields_ = [("x", ctypes.c_int), ("y", ctypes.c_int)]  # 创建结构体的实例  
p = Point()  
p.x = 10  
p.y = 20  # 将结构体的实例传递给C函数  
lib.print_point(p)  # 假设有一个print_point函数用于打印点的坐标

6 处理字符串

字符串通常以字符数组或字符指针的形式存在。在ctypes中,你可以使用create_string_buffer来创建C风格的字符串,或者使用c_char_p来操作字符串指针。

python"># 创建C风格的字符串  
c_str = ctypes.create_string_buffer(b"Hello, World!")  # 将字符串传递给C函数  
lib.print_string(c_str)  # 假设有一个print_string函数用于打印字符串  # 处理C语言中的字符串指针  
c_char_p_type = ctypes.POINTER(ctypes.c_char)  
c_char_p = c_char_p_type.from_buffer(c_str)  
lib.print_string_ptr(c_char_p)  # 假设有一个print_string_ptr函数接收字符串指针

7 回调函数

c 中很多实现异步的方式通过回调函数事件触发的方式,ctype中也能将ctype定义的函数传入c中执行

# include "stdio.h"typedef int (*CallbackFunc)(int, int);int c_sub(int x, int y){printf("c callback func\n");return x - y;
}void call_callback(CallbackFunc callback){int result = callback(3, 4);printf("result from c: %d\n", result);
}
python">import ctypesmy_lib = ctypes.CDLL("./test2.so")callback_type = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int)def python_sub(a, b):print("python callback func")return b - a# 1.调用c中的函数,回调函数从python中传入
python_callback = callback_type(python_sub)
my_lib.call_callback(python_callback)# 2.调用c中的函数,回调从c中传入
c_callback = callback_type(my_lib.c_sub)
my_lib.call_callback(c_callback)

http://www.ppmy.cn/news/1431138.html

相关文章

力扣爆刷第124天之回溯五连刷

力扣爆刷第124天之回溯五连刷(分割回文、复原IP、子集) 文章目录 力扣爆刷第124天之回溯五连刷(分割回文、复原IP、子集)一、131. 分割回文串二、93. 复原 IP 地址三、78. 子集四、90. 子集 II五、91. 非递减子序列 一、131. 分割…

ACM生涯总结

大一时迷恋上了算法竞赛,抓紧一切课余时间进行训练,也顺利了进入了学校的ACM-ICPC集训队。 大二以为能够拿到银牌,但命运和我开了个玩笑,连续两次拿到铜首(一次差一名,一次差两名)。 大三上的…

Qt Android 无法加载 assets 目录下 lua 校准脚本

问题描述 C 语言使用 fopen 无法打开 assets 目录下的文件。 项目的校准脚本在打包的时候都放在 assets 资源目录下,但是 assets 是压缩包,Android 下虚拟目录,所以 Qt 可以加载 assets 目录下文件,但是 C 语言的 fropen 函数却…

了解边缘计算,在制造行业使用边缘计算。

边缘计算是一种工业元宇宙技术,可以帮助组织实现其数据的全部潜力。 处理公司的所有数据可能具有挑战性,而边缘计算可以帮助公司更快地处理数据。在制造业中,边缘计算可以帮助进行预测性维护和自动驾驶汽车操作等工作。 什么是边缘计算? …

市场投放用户获取方面如何做数据分析

常用数据分析指标 1. 基础指标 下载量: 指通过广告投放带来的下载安装量。 安装率: 指广告点击后下载安装的用户占比。 激活率: 指下载安装后启动应用的用户占比。为了防止假量和刷量,一般会把激活动作定义得更严格更深层一些。比如用户浏览30秒,用户…

力扣(leetcode) 407. 接雨水 II 3D接雨水

力扣(leetcode) 407. 接雨水 II 3D接雨水 给你一个 m x n 的矩阵,其中的值均为非负整数,代表二维高度图每个单元的高度,请计算图中形状最多能接多少体积的雨水。 示例 1: 输入: heightMap [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]] 输…

Macs Fan Control Pro for Mac:全面优化Mac风扇控制软件

Macs Fan Control Pro for Mac是一款专为苹果电脑用户设计的风扇控制软件,旨在通过精确的风扇速度调节,全面优化Mac的散热性能,确保系统始终运行在最佳状态。 Macs Fan Control Pro for Mac中文版下载 该软件具备实时监控功能,能够…

【WSL报错】执行:wsl --list --online;错误:0x80072ee7

【WSL报错】执行:wsl --list --online;错误:0x80072ee7 问题情况解决方法详细过程 问题情况 C:\Users\17569>wsl --list --online 错误: 0x80072ee7 解决方法 开系统代理,到外网即可修复!!!!&#x…