Linux下 Python通过ctypes调用cAPI (一)

c_long和c_int是一种类型。
cdll加载使用标准cdecl调用约定导出函数的库
windll使用stdcall调用约定调用函数
oledll也使用stdcall调用约定

在linux下通过两种方法加载动态链接库
1.cdll.LoadLibrary("libc.so.6")
2.CDLL("libc.so.6")
(结果相同)

如何告诉Python一个外来函数的形参类型和返回的值的类型呢

答:给函数的两个属性restype和argtypes赋值。
restype-------返回类型
argtypes------参数类型
例如某函数的返回类型是float,对应到Python里就是c_float。
dll.addf.restype = c_float

如果函数的返回值是void那么可以赋值为None。另外,可以使用python 内置类型“描述”库函数的返回类型,但是,不可以用python内置类型来描述库函数的参数类型。


由于函数的参数不是固定的数量,所以需要使用列表或者是元祖来说明:
dll.addf.argtypes = (c_float,c_float)
or
dll.addf.argtypes = [c_float,c_float]

创建一个ctypes的类型(c_int、c_float、c_char...)并给他赋值
i = c_int(45)
i.value
or
i.value = 56
i.value

结构体跳过

指针
创建一个ctypes的指针:
1.byref(x[,offset]):返回x的地址,x必须为ctypes类型的一个实例。相当于c的&x。offset表示偏移量。(通过引用传递参数)
2.pointer(x):创建并返回一个指向x的指针实例,x是一个实例对象。(构造了一个真正的指针对象,因此这种方法做了很多工作,会更慢相对byref)
3.POINTER(type):返回一个类型,这个类型是指向type类型的指针类型,type是ctypes的一个类型。
eg:
>>> a = c_int(66)         # 创建一个 c_int 实例
>>> b = pointer(a)        # 创建指针
>>> c = POINTER(c_int)(a) # 创建指针
>>> b
<__main__.LP_c_long object at 0x00E12AD0>
>>> c
<__main__.LP_c_long object at 0x00E12B20>
>>> b.contents            # 输出 a 的值
c_long(66)
>>> c.contents            # 输出 a 的值
c_long(66)

令POINTER(c_int)为pointer

pointer创建的指针貌似不能修改ctypes类型

print_point函数:
>>> dll.print_point.argtypes = (POINTER(Point),)   # 指明函数的参数类型
>>> dll.print_point.restype = None                 # 指明函数的返回类型
>>>
>>> p = Point(32.4, -92.1)      # 实例化一个 Point
>>> dll.print_point(byref(p))   # 调用函数
position x 32.400002 y -92.099998>>>

当然你非要用慢一点的 pointer 也行:

>>> dll.print_point(pointer(p))  # 调用函数
position x 32.400002 y -92.099998

关于byref()-即用引用传递参数:
一般适用于需要C函数修改传入的参数,或者参数过大不适合传值,这时就要用到按引用传递。
eg:
from ctypes import *
'''
windows下
libc = cdll.LoadLibrary('msvcrt.dll')
'''
#linux下
libc = cdll.LoadLibrary('libc.so.6')
    
i = c_int()
f = c_float()
s = create_string_buffer(b'\000' * 32)
print 'i.val =', i.value
print 'f.val =', f.value
print 'repr(s.value) =', repr(s.value)
libc.sscanf(b'1 3.14 Hello', b'%d %f %s', byref(i), byref(f), s)
#3表示正确返回,0 表示不正确返回
print 'after, i.val =', i.value
print 'after, f.val =', f.value
print 'after, repr(s.value) =', repr(s.value)
输出:
i.val = 0
f.val = 0.0
repr(s.value) = ''
after, i.val = 1
after, f.val = 3.1400001049
after, repr(s.value) = 'Hello'

数组
数组是序列,包含固定数量的相同类型的实例。
推荐的创建数组类型的方法是将数据类型乘以正整数:
TenPointsArrayType  =  POINT  *  10
官方文档给出的例子是eg:
>>> from  ctypes  import  *
>>> class  POINT (Structure ):
...     _fields_  =  (“x” , c_int ), (“y” , c_int )
...
>>> class  MyStruct (Structure ):
.. 。    _fields_  =  [( “ 一” , c_int的),
...                 (“b” , c_float ),
...                 (“point_array” , POINT  * 4 )]
>>>
>>> print (len (MyStruct ()。point_array ))
4

更好的例子eg:
>>> class POINT(Structure):
#括号里第一个参数是形参的名字
...     _fields_=("x",c_int),("y",c_int)
...
>>> class MyStruct(Structure):
...     _fields_=[("a",c_int),("b",c_float),("point_array",POINT*4)]
...
>>> print(len(MyStruct().point_array))
4
>>> TenIntArrayType = c_int * 10
#如果不赋值,默认是0
>>> ta = TenIntArrayType(1,2,3,4,5,6,7,8,9,10)
>>> for item in ta:
...     print(item)
...
1
2
3
4
5
6
7
8
9
10
>>> ms = MyStruct(4,5,((1,1),(2,2),(3,3),(4,4)))
>>> for item in ms.point_array:
...     print('(item.x,item.y) = (%d,%d)' % (item.x,item.y))
...
(item.x,item.y) = (1,1)
(item.x,item.y) = (2,2)
(item.x,item.y) = (3,3)
(item.x,item.y) = (4,4)
>>>

pointer()函数指针:
>>> from ctypes import *
>>> i = c_int(42)
>>> pi = pointer(i)
>>> pi.contents
c_long(42)
注意ctypes都没有原始对象返回,也就是说每次调用pi属性时重新创建一个新的对象,那么就是:
>>> pi.contents is i
False
>>> pi.contents is pi.contents
False
在幕后,pointer()不仅创建指针实例,它必须首先创建指针类型。这是通过POINTER()接受任何ctypes类型的函数完成的,并返回一个新类型。
调用没有参数的指针类型将创建一个NULL指针。 NULL指针有一个False布尔值:
>>> null_ptr  =  POINTER (c_int )()
>>> print (bool (null_ptr ))
False
>>>


参考:点击打开链接

点击打开链接

这个↓是各种类型参数从python向c传递的教程!!!

点击打开链接

可以通过以下步骤通过 ctypes 调用海康网络 SDK 保存视频: 1. 首先,你需要安装海康网络 SDK,并确保能够正常运行。SDK 提供了一些 C 风格的 API,你可以通过 ctypes 调用它们。 2. 在 Python 中导入 ctypes 模块,并使用 ctypes.cdll.LoadLibrary() 函数加载 SDK 的动态链接库。例如: ```python import ctypes hk_sdk = ctypes.cdll.LoadLibrary("NetSdk.dll") ``` 3. 定义需要使用的函数原型。你可以在 SDK 的文档中找到这些信息。例如,如果你需要调用 SDK 中的 NET_DVR_SaveRealData() 函数来保存实时视频流,你可以这样定义它的原型: ```python hk_sdk.NET_DVR_SaveRealData.restype = ctypes.c_bool hk_sdk.NET_DVR_SaveRealData.argtypes = [ctypes.c_long, ctypes.c_char_p] ``` 这里的 restype 表示函数的返回类型,argtypes 表示函数的参数类型。注意,参数类型需要使用 ctypes 提供的类型,例如 ctypes.c_long 表示 long 类型,ctypes.c_char_p 表示 char* 类型。 4. 调用函数。在调用函数时,需要将参数转换为 ctypes 类型。例如,如果你需要保存通道号为 1 的视频流到文件 "D:\\test.mp4" 中,可以这样调用函数: ```python channel = 1 filename = b"D:\\test.mp4" success = hk_sdk.NET_DVR_SaveRealData(channel, filename) ``` 这里的 b"D:\\test.mp4" 表示将 Python 的字符串转换为 C 风格的字符串。 注意,调用函数时需要根据函数的返回值来判断操作是否成功。在这个例子中,函数返回一个 bool 值,表示是否保存成功。 以上是一个简单的示例,具体的实现可能需要根据实际情况进行调整。另外,需要注意的是,海康网络 SDK 可能会涉及到一些特殊的编码和协议,需要仔细阅读文档并进行相应的配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值