Python 如何给 c 函数传递结构体参数?有人知道吗

2018-03-17 15:37:46 +08:00
 pyse

项目中现在遇到这么一个问题,函数是用 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 -----

求各位指教,谢谢大家

2691 次点击
所在节点    Python
9 条回复
wwqgtxx
2018-03-17 16:09:11 +08:00
问题在于 byref 实际上是传递了指针进去,而你需要的是直接传递结构体,而不是一个指向结构体的指针
pyse
2018-03-17 16:10:49 +08:00
@wwqgtxx 我直接传结构体也是一样无效啊

```python
lib.Display(su)
```
wwqgtxx
2018-03-17 16:11:46 +08:00
你试试
lib.Display.argtypes = [Student]
lib.Display(su)
这样能不能工作
wwqgtxx
2018-03-17 16:14:23 +08:00
另外,你的 Student 类定义的并不对,你也需要在 python 中为 name[30]保持同样的定义,而不是一个 c_char_p,应该是 c_char*30
pyse
2018-03-17 16:17:59 +08:00
@wwqgtxx
厉害厉害。直中要害,用你这个办法,确实传递成功了!!!,太感谢了!!!!!!

-----Information------
Name:test34954
Chinese:15.10
Math:13.20
English:51.30
平均分数为:17.10
----- finish -----
pyse
2018-03-17 16:19:49 +08:00
@wwqgtxx
我后来也发现了,改过来了。因为不懂 C,都是参照网上例子照猫画虎。。总之,万分感谢,我这个问题,搞了 2 天了,早知道就早些在 V2EX 求助了
pyse
2018-03-17 16:23:39 +08:00
@wwqgtxx 追问一下,lib.Display.argtypes = [Student] 这一行代码是做了什么操作啊,看不太明白?
wwqgtxx
2018-03-17 16:25:21 +08:00
@pyse 指定传入参数的类型呀,实际上就是把参数压入堆栈,这个地方不指定默认是 c_int 所以肯定不对呀
pyse
2018-03-17 16:26:57 +08:00
@wwqgtxx 哦哦,感谢老铁,我再学习一下,哈哈

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/438914

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX