Python&C++混合编程-结构体参数传递
前言
本章介绍的是在使用Python&C++混合编程时,如何实现结构体参数的相互传递。混合编程的方式是由C++编写Python扩展库,然后直接在Python中import
使用,这种方式于直接调用C++编写的动态连接库的实现方式不同。
一、结构体定义
- Python代码定义
class test_st(Structure):
_fields_ = [
('b1', c_uint8),
('b2', c_uint8),
('fp_bs', POINTER(c_uint8))
]
在Python中我们把结构体定义成一个类,这个类必须继承于Structure
,在类中定义一个_fields_
列表,并在其中以元组的方式列举结构体的成员变量。
元组内格式为(变量名称, 变量类型)。
- C++代码定义
typedef struct
{
uint8_t b1;
uint8_t b2;
uint8_t* fp_bs;
}TEST_ST;
二、实现方式
- Python代码定义
from ctypes import *
import mymod
tt = test_st()
tt.b1 = 3
tt.b2 = 4
fp_bs = bytes([21, 22, 23])
BUFFER = c_char * len(fp_bs)
buffer = BUFFER()
memmove(buffer, fp_bs, len(fp_bs))
tt.fp_bs = cast(pointer(buffer), POINTER(c_uint8))
mymod.test(tt)
代码中必须要引用ctypes下的全部类型,这里定义了python和C++之间的转换类型。
mymod是我编写的C++扩展库。
- C++代码定义
#include <stdio.h>
#include <memory.h>
#include <sys/time.h>
#include <Python.h>
//定义测试结构体
typedef struct
{
uint8_t b1;
uint8_t b2;
uint8_t* fp_bs;
}TEST_ST;
//测试函数
static PyObject* mymod_test(PyObject* self, PyObject* args)
{
printf("C++ - 测试结构体参数传递\r\n");
PyObject* args1;
//获取入口参数
PyArg_ParseTuple(args, "O", &args1);
//通过入口参数获取结构体指针
Py_buffer data = {NULL, NULL};
if(PyObject_GetBuffer(args1, &data, PyBUF_SIMPLE) != 0)
{
printf("C++ - 参数读取失败\r\n");
return Py_None;
}
printf("C++ - 参数读取成功\r\n");
//将指针转换为结构体指针
TEST_ST* st = (TEST_ST*)data.buf;
printf("C++ - 参数值:len-%lu, %x, %x, %x, %x, %x\r\n", sizeof(st), st->b1, st->b2, st->b3[0],st->b3[1],st->b3[2]);
//在这里修改了结构体的变量,则Python中也会跟着改变
st->b1 = 31;
return Py_None;
}
#define MYMOD_TEST \
{ "test", (PyCFunction)mymod_test, METH_VARARGS, "test(Structure)." },
static PyMethodDef mymod_methods[] = {
MYMOD_TEST
{NULL, NULL, 0, NULL}
};
static PyModuleDef mymod_module = {
PyModuleDef_HEAD_INIT,
"mymod",
"结构体参数传递测试类",
0,
mymod_methods
};
PyMODINIT_FUNC PyInit_mymod(void)
{
return PyModule_Create(&mymod_module);
}
三、指针转换
本例的结构体中存在一个指针变量fp_bs
,进行定义时我使用POINTER(数据类型)
来指定变量是一个指针类型。在进行变量赋值时也需要给定指针,以本例来说,我们定义了一个字节数组,在Python代码中定义一个bytes(),长度是3个字节。我们使用ctypes
提供的类型转换方法 cast()
将bytes转换为字节数值指针,实现如下
# 定义一个字节数组类
fp_bs = bytes([21, 22, 23])
# 将字节数组类转换为在内存里的字节数组
BUFFER = c_char * len(fp_bs)
buffer = BUFFER()
memmove(buffer, fp_bs, len(fp_bs))
# 获取字节数组的指针
tt.fp_bs = cast(pointer(buffer), POINTER(c_uint8))