python--ctypes库调用初体验

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

主要是记录python调用C接口一些注意事项。
ctypes传送门:ctypes库
环境是linux。

一、库的环境变量设置

一般在登陆用的home目录下更改
vim .profile
export LF_LIBRARY_PATH="so文件目录"
souce .profile

二、初识ctypes

加载库:

 path = os.path.abspath(so文件的绝对路径)#
 my_cdll = cdll.LoadLibrary(path)
 my_cdll.接口名()

2.1 数据对应关系

在这里插入图片描述

2.2 指针

2.2.1 传递指针

若一个接口API如下:
如果接口中存在VOID则不需要传参,TEST(VOID)

	TEST_API int 	TEST(IN int      resolution_type, 
                                            OUT int *   width, 
                                            OUT int *   height);

输出参数需要指针接收,则可使用pointer(),查看pointer函数:

# The real ctypes.pointer is a function, not a class. The stub version of pointer behaves like
# ctypes._Pointer in that it is the base class for all pointer types. Unlike the real _Pointer,
# it can be instantiated directly (to mimic the behavior of the real pointer function).
class pointer(Generic[_CT], _PointerLike, _CData):
    _type_: ClassVar[Type[_CT]] = ...
    contents: _CT = ...
    def __init__(self, arg: _CT = ...) -> None: ...
    @overload
    def __getitem__(self, i: int) -> _CT: ...
    @overload
    def __getitem__(self, s: slice) -> List[_CT]: ...
    @overload
    def __setitem__(self, i: int, o: _CT) -> None: ...
    @overload
    def __setitem__(self, s: slice, o: Iterable[_CT]) -> None: ...

ctypes中使用POINTER和pointer表示指针,在使用POINTER时需要设置指向的数据类型,而pointer则直接从变量中得到一个特定类型的指针。
POINTER相当于只是申明数据类型,真正传递是需要pointer()
示例:

class XXXXX(SdkBase):

    def run(self):
        self.cdll.TEST.argtype = (c_int,POINTER(c_int),POINTER(c_int))#定义输入数据类型
        self.cdll.TEST.restype = c_int#定义返回数据类型
        self.width = c_int()
        self.height = c_int()
        code = self.cdll.TEST(self.resolution_type,pointer(self.width),pointer(self.height))

2.3 结构体

结构体和联合必须继承自 ctypes 模块中的 Structure 和 Union 。子类必须定义 fields 属性。 fields 是一个二元组列表,二元组中包含 field name 和 field type 。

type 字段必须是一个 ctypes 类型,比如 c_int,或者其他 ctypes 类型: 结构体、联合、数组、指针。

from ctypes import *


class struct_Config(Structure):
	_fields_ = [
				('addr', (c_char * 32)),
				('port', c_uint16),
				('username', (c_char * 32)),
				('password', (c_char * 32)),
				('chan_no', c_uint16),
				('chan_profile', c_uint16),
				('model', (c_char * 32)),
				('rtsp_url', (c_char * 512))
				]
class union_IotDeviceConfig(Union):
	_fields_ = [#联合模式

				('url', struct_Config)
				]
class Test:
			#struct_IotIpcConfig结构体
            _arg = struct_IotIpcConfig()
            _arg.addr = (args.get('addr', '')).encode('utf-8')
            _arg.port = int(args.get('port', 0))
            _arg.username = (args.get('username', '')).encode('utf-8')#如果是字符串则需要编码

2.4 数组

char addr[IOT_LEN_ADDR] ---> ('addr', (c_char * 32))

2.5 回调函数

CFUNCTYPE() 工厂函数使用 cdecl 调用约定创建回调函数类型。在 Windows 上, WINFUNCTYPE() 工厂函数使用 stdcall 调用约定为回调函数创建类型。

IOT_API int STDCALL TEST(IN CALLBACK cb, 
                                      IN void *             user_data);
class Test_s(SdkBase):
    def __init__(self, args=None):
    
        CALLBACK = CFUNCTYPE(c_int, POINTER(struct_Info),c_int,c_char_p)#定义回调函数中需要的参数
        self.system_define_cb = CALLBACK(self.system_define_cb_func)#定义函数名

    def run(self):
        self.cdll.IOT_GetDeviceList.argtype = (c_int,c_char_p)
        self.cdll.IOT_GetDeviceList.restype = c_int
        code = self.cdll.TEST(self.system_define_cb,self.user_data)#调用API

        return self.result(code, {'result': self.res})

    def result(self, code, res=None):
        return super().result(code, res)

    def system_define_wait_func(self):
        time.sleep(2)

    def system_define_cb_func(self, dev_list, dev_num, user_data):
        return self.real_cb_func(dev_list,dev_num,user_data)

    def real_cb_func(self, dev_list,dev_num, user_data):
  
        return 0
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值