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函数传递结构体参数?有人知道吗

9 回复

问题在于 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 所以肯定不对呀

哦哦,感谢老铁,我再学习一下,哈哈

回到顶部