Python中如何给C函数传递结构体参数?有人知道吗
项目中现在遇到这么一个问题,函数是用 c 写的,调用要用到 python,因为是在 linux 环境,所以是直接调用的动态库 SO 文件,调用方式我已经搞定了,但是不知道怎么用 pyton 给 c 函数传递结构体参数,网上找了一些例子,但没调通,不知道是哪里不对,请教各位了,帖一下简单的代码例子:
//test1.c
include <stdio.h>
include <stdlib.h>
struct Student
{
char name[30];
float fScore[3];
};
void Display(struct Student su)
{
printf("-----Information------\n");
printf(“Name:%s”,su.name);
printf(“Chinese:%.2f\n”,su.fScore[0]);
printf(“Math:%.2f\n”,su.fScore[1]);
printf(“English:%.2f”,su.fScore[2]);
printf(“平均分数为:%.2f\n”,(su.fScore[0]+su.fScore[1],su.fScore[2])/3);
}
以上代码编辑成动态库 libpycall.so 文件了
gcc -o libpycall.so -shared -fPIC test1.c
python 调用 c 的代码:
#pycall.py
import ctypes
from ctypes import *
class Student(Structure):
fields = [(“param1”,c_char_p),
(“param2”, c_float * 3)
]
su = Student()
su.param1 = b"testsdk"
PARAM = c_float * 3
param2 = PARAM()
param2[0] = 1.1
param2[1] = 1.2
param2[2] = 1.3
su.param2 = param2
if name == ‘main’:
ll = ctypes.cdll.LoadLibrary
lib = ll("./libpycall.so")
lib.Display(byref(su))
print('----- finish -----')
============================================================
我期望的结果是按以下代码执行
//test1_demo.c
include <stdio.h>
include <stdlib.h>
//创建一个 Student 结构体
struct Student
{
char name[30];
float fScore[3];
};
struct Student su = {“testsdk”,98.5,89.0,93.5};
void Display(struct Student su)
{
printf("-----Information------\n");
printf(“Name:%s\n”,su.name);
printf(“Chinese:%.2f\n”,su.fScore[0]);
printf(“Math:%.2f\n”,su.fScore[1]);
printf(“English:%.2f\n”,su.fScore[2]);
printf(“平均分数为:%.2f\n”,(su.fScore[0]+su.fScore[1],su.fScore[2])/3);
}
int main ()
{
Display(su);
return 0;
}
输出(这是我想用 python 调用的期望结果)
-----Information------
Name:testsdk
Chinese:98.50
Math:89.00
English:93.50
平均分数为:31.17
[Finished in 0.3s]
但我用 python 调用的时候,传递的结构体识别不了,都是空的,应该是没识别是结构体
-----Information------
Name:
Chinese:0.00
Math:0.00
English:0.00
平均分数为:0.00
----- finish -----
求各位指教,谢谢大家
Python中如何给C函数传递结构体参数?有人知道吗
问题在于 byref 实际上是传递了指针进去,而你需要的是直接传递结构体,而不是一个指向结构体的指针
在Python中给C函数传递结构体参数,主要用ctypes库。你需要先定义与C结构体对应的Python类,然后创建实例并作为指针传递。下面是个完整例子:
假设C库mylib.so中有这个函数:
// mylib.h
typedef struct {
int x;
float y;
char name[32];
} MyStruct;
void process_struct(MyStruct *data);
Python端这样调用:
import ctypes
from ctypes import c_int, c_float, c_char
# 1. 定义对应结构体
class MyStruct(ctypes.Structure):
_fields_ = [
('x', c_int),
('y', c_float),
('name', c_char * 32)
]
# 2. 加载库
lib = ctypes.CDLL('./mylib.so')
# 3. 设置函数原型
lib.process_struct.argtypes = [ctypes.POINTER(MyStruct)]
lib.process_struct.restype = None
# 4. 创建结构体实例并赋值
data = MyStruct()
data.x = 42
data.y = 3.14
data.name = b"test_data"
# 5. 传递指针调用
lib.process_struct(ctypes.byref(data))
关键点:
_fields_必须严格匹配C结构体的声明顺序和类型- 字符串字段用
c_char * 长度定义 - 通过
ctypes.byref()传递指针 - 设置
argtypes能确保类型安全检查
如果结构体里有嵌套或指针成员,定义会复杂些,但基本模式不变。
你试试
lib.Display.argtypes = [Student]
lib.Display(su)
这样能不能工作
另外,你的 Student 类定义的并不对,你也需要在 python 中为 name[30]保持同样的定义,而不是一个 c_char_p,应该是 c_char*30
厉害厉害。直中要害,用你这个办法,确实传递成功了!!!,太感谢了!!!!!!
-----Information------
Name:test34954
Chinese:15.10
Math:13.20
English:51.30
平均分数为:17.10
----- finish -----
我后来也发现了,改过来了。因为不懂 C,都是参照网上例子照猫画虎。。总之,万分感谢,我这个问题,搞了 2 天了,早知道就早些在 V2EX 求助了
追问一下,lib.Display.argtypes = [Student] 这一行代码是做了什么操作啊,看不太明白?
指定传入参数的类型呀,实际上就是把参数压入堆栈,这个地方不指定默认是 c_int 所以肯定不对呀
哦哦,感谢老铁,我再学习一下,哈哈

