V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
pyse
V2EX  ›  Python

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

  •  
  •   pyse · 2018-03-17 15:37:46 +08:00 · 2640 次点击
    这是一个创建于 2232 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    求各位指教,谢谢大家

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

    ```python
    lib.Display(su)
    ```
    wwqgtxx
        3
    wwqgtxx  
       2018-03-17 16:11:46 +08:00 via iPhone
    你试试
    lib.Display.argtypes = [Student]
    lib.Display(su)
    这样能不能工作
    wwqgtxx
        4
    wwqgtxx  
       2018-03-17 16:14:23 +08:00 via iPhone
    另外,你的 Student 类定义的并不对,你也需要在 python 中为 name[30]保持同样的定义,而不是一个 c_char_p,应该是 c_char*30
    pyse
        5
    pyse  
    OP
       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
        6
    pyse  
    OP
       2018-03-17 16:19:49 +08:00
    @wwqgtxx
    我后来也发现了,改过来了。因为不懂 C,都是参照网上例子照猫画虎。。总之,万分感谢,我这个问题,搞了 2 天了,早知道就早些在 V2EX 求助了
    pyse
        7
    pyse  
    OP
       2018-03-17 16:23:39 +08:00
    @wwqgtxx 追问一下,lib.Display.argtypes = [Student] 这一行代码是做了什么操作啊,看不太明白?
    wwqgtxx
        8
    wwqgtxx  
       2018-03-17 16:25:21 +08:00
    @pyse 指定传入参数的类型呀,实际上就是把参数压入堆栈,这个地方不指定默认是 c_int 所以肯定不对呀
    pyse
        9
    pyse  
    OP
       2018-03-17 16:26:57 +08:00
    @wwqgtxx 哦哦,感谢老铁,我再学习一下,哈哈
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2254 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 00:53 · PVG 08:53 · LAX 17:53 · JFK 20:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.