高级语言调用C接口(四)结构体(2)-Python
这个专栏好久没有更新了,主要是坑开的有点大,也不知道怎么填,涉及到的开发语言比较多,写起来比较累,需要看的人其实并不多,只能说,慢慢填吧,中间肯定还会插很多别的东西,更新频率自己也不知道。
上一次说了Java和C#调用C接口传递结构体,今天来说一下Python。由于鸿蒙并不需要在arkts层真正的定义结构体,Napi层可以通过Json转结构体的方式来实现,还没想好怎么去举例子,下次再说吧。
Python这种脚本语言并没有结构体的概念,所以我们要用到Python的ctypes包中的Structure。
和Java、C#一样,由于高级语言的结构与C的结构体并不完全一样,高级语言的类包含方法,而C的结构体是定义即所见,所以C接口直接调用高级语言的结构体数组地址时,会崩溃,Python也和C#、Java一样,定义为数组并赋值,再将数组转换为连续内存。
from ctypes import *
import sys
# 定义结构体(需与C头文件完全一致)
class stGoodsInfo(Structure):
_fields_ = [
("goodsId", c_char_p),
("goodsName", c_char_p),
("quantity", c_char_p),
("price", c_char_p),
("goodsCategory", c_char_p),
("body", c_char_p),
("discount", c_char_p),
("unit", c_char_p)
]
class stOrderInfo(Structure):
_fields_ = [
("merOrderId", c_char_p),
("srcReserve", c_char_p),
("orderDesc", c_char_p),
("totalAmount", c_char_p),
("goodsNum", c_int),
("pstGoodsInfo", POINTER(stGoodsInfo)),
("attachedData", c_char_p)
]
# 加载动态库(示例名称,需替换实际库路径)
lib = CDLL("XXX.so") # Linux/Mac
# lib = WinDLL("XXX.dll") # Windows
# 定义函数原型
lib.PalmPay.argtypes = [POINTER(stOrderInfo)]
lib.PalmPay.restype = None
def main():
# 创建商品数组(保持内存连续)
goods_array = (stGoodsInfo * 2)()
# 填充第一个商品
goods_array[0] = stGoodsInfo(
goodsId=b"SDGOOD000001",
goodsName="哇哈哈矿泉水".encode('utf-8'),
quantity=b"2",
price=b"2.00",
goodsCategory="食品饮料".encode('utf-8'),
body="饮料".encode('utf-8'),
discount=b"0",
unit="瓶".encode('utf-8')
)
# 填充第二个商品
goods_array[1] = stGoodsInfo(
goodsId=b"SDGOOD000002",
goodsName="百岁山矿泉水".encode('utf-8'),
quantity=b"2",
price=b"3.00",
goodsCategory="食品饮料".encode('utf-8'),
body="饮料".encode('utf-8'),
discount=b"0",
unit="瓶".encode('utf-8')
)
# 创建订单结构体
order = stOrderInfo()
order.merOrderId = b"SD000000000000001"
order.srcReserve = b"aaaaaaaaaaaaaa"
order.orderDesc = b"Test"
order.totalAmount = b"10.00"
order.attachedData = b"attachedData test"
order.goodsNum = 2
order.pstGoodsInfo = cast(goods_array, POINTER(stGoodsInfo)) # 关键指针转换
# 调用C接口(传递结构体指针)
lib.PalmPay(byref(order))
if __name__ == "__main__":
main()